Skip to content

Add --parallel support to tests command for safe, zero-workaround parallel PHPUnit execution #8

@coisa

Description

@coisa

Description

Problem

The current tests command only runs PHPUnit in a single process. For medium and large test suites, this increases execution time unnecessarily and makes local feedback loops and CI pipelines slower than they need to be.

At the same time, adding parallel execution in a naive way often introduces practical problems such as unstable coverage output, resource contention, or the need for test-suite-specific workarounds. The goal here is not to expose a parallel mode that works only in ideal cases, but to provide one that is safe, predictable, and usable in common real-world projects without forcing drastic changes to existing tests.

Proposal

Add a new option to the command:

dev-tools tests --parallel

Suggested behavior:

  • --parallel enables parallel execution transparently
  • default behavior remains unchanged when the flag is absent
  • the implementation should preserve the current command contract as much as possible
  • coverage, filtering, bootstrap, config, and cache options should continue to work consistently in parallel mode

An optional extension could be:

dev-tools tests --parallel[=N]

Where:

  • --parallel uses an automatic worker count
  • --parallel=4 forces a specific number of workers

Implementation direction

The most practical default appears to be integrating ParaTest, whose stated goal is parallel execution for PHPUnit, with “zero configuration” for well-written PHPUnit suites, support for running across multiple processes, and combined code-coverage reporting. 

A possible strategy:

  • keep vendor/bin/phpunit as the default runner
  • switch to vendor/bin/paratest when --parallel is enabled
  • preserve existing options by translating them to the parallel runner when compatible
  • keep output and exit-code behavior aligned with the current command

Requirements

This feature should aim for the following guarantees:

  • parallel mode MUST be opt-in
  • enabling --parallel MUST NOT require consumers to redesign their test suite
  • the common case should work without custom bootstrap hacks, per-process shell scripts, or intrusive test rewrites
  • code coverage should still be supported in a first-class way
  • the implementation should avoid surprising behavior differences between serial and parallel execution

Non-goals

This issue is not requesting a “best effort” parallel mode that pushes complexity to the user. In particular, the solution should avoid requiring common consumers to:

  • manually shard suites
  • rewrite large portions of integration tests
  • introduce custom process-token plumbing in application code
  • maintain separate bootstrap files just to make parallel execution usable

Notes on common pitfalls

Parallel execution tools can expose contention when tests share mutable resources such as databases, filesystem state, or caches. ParaTest itself documents that these issues can occur in suites that are not isolated around shared resources. 

Because of that, this feature should be designed around safe defaults and a strong expectation that the command abstraction handles the common path cleanly. That may include implementation details such as:

  • selecting a stable runner mode by default
  • preserving PHPUnit configuration semantics
  • handling coverage aggregation automatically
  • documenting only minimal, non-invasive expectations around test isolation

Possible approaches

1. ParaTest-backed runner

Use ParaTest when --parallel is enabled. This is likely the best default because it is purpose-built for parallel PHPUnit execution and explicitly supports combined coverage output. 

2. Automatic worker-count strategy

Detect a sensible worker count automatically, with an override available through --parallel=N.

3. Conservative compatibility mode

If some PHPUnit arguments are not safe in a given parallel mode, the command should handle that internally rather than forcing the user to discover caveats by trial and error.

4. Optional future extension

A later enhancement could expose a more advanced mode for projects that want finer-grained scheduling, but the first implementation should optimize for zero-friction adoption.

Expected behavior

Example:

dev-tools tests --parallel
dev-tools tests --parallel=8 --filter=UserServiceTest
dev-tools tests --parallel --coverage=./tmp/coverage

Expected result:

  • faster execution for most suites
  • no behavioral regression when the flag is omitted
  • no drastic test-code modifications required for ordinary adoption
  • no extra workaround layer required just to make the flag usable

Benefits

  • significantly faster local test feedback
  • faster CI pipelines
  • better developer experience
  • adoption path that stays aligned with existing PHPUnit usage
  • keeps the abstraction at the dev-tools tests level instead of making each consumer assemble its own parallel strategy

Additional Context

There are other ways to parallelize test execution, including distributing test workloads across CI jobs instead of parallelizing inside one process host, but that solves a different layer of the problem. This issue is specifically about adding local command-level parallel execution behind the existing tests command.

Metadata

Metadata

Assignees

No one assigned

    Labels

    enhancementNew feature or request

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions