Introducing Test Splitter

July 6th 2026 open source test splitter


What is Test Splitter?

Test Splitter is a small open source tool that splits a PHPUnit test suite into batches, in a deterministic way. Each batch can then be run in a separate CI job. If your test suite takes 20 minutes to run, splitting it over 4 parallel jobs gets feedback to the team in roughly 5 minutes.

I built it in 2021 to solve a problem on a couple of client projects: test suites that had grown to the point where the feedback loop was painfully slow, on CI platforms that made it easy to run jobs in parallel but offered no way to divide the tests between them.

How it works

Install it with composer:

composer require --dev dave-liddament/test-splitter

The package provides a single executable, vendor/bin/tsplit, which takes two arguments: the batch number and the total number of batches. It reads a list of tests from stdin and writes the tests belonging to the requested batch to stdout.

Combine it with PHPUnit's --list-tests and --filter options to run just one batch of tests. For example, to split the suite into 4 batches and run the first one:

vendor/bin/phpunit --filter `vendor/bin/phpunit --list-tests | vendor/bin/tsplit 1 4`

Because the split is deterministic, every job that asks for batch 1 of 4 gets the same tests, and the batches never overlap or miss a test.

Using it in CI

The tool really pays off in CI pipelines. With GitHub Actions, use a matrix to run each batch as its own job:

jobs:
  tests:

    strategy:
      fail-fast: false
      matrix:
        test-batch: [1, 2, 3, 4]

    steps:
      # Steps to checkout code, setup environment, etc.

      - name: "Tests batch ${{ matrix.test-batch }}"
        run: vendor/bin/phpunit --filter `vendor/bin/phpunit --list-tests | vendor/bin/tsplit ${{ matrix.test-batch }} 4`

GitLab CI/CD makes it even simpler. Its predefined variables CI_NODE_INDEX and CI_NODE_TOTAL supply the batch numbers automatically:

test:
  stage: test
  parallel: 4
  script:
    - vendor/bin/phpunit --filter `vendor/bin/phpunit --list-tests | vendor/bin/tsplit ${CI_NODE_INDEX} ${CI_NODE_TOTAL}`

Alternatives

Test Splitter is deliberately a very simple tool. When it was created in 2021 nothing else did the job; that's no longer true. If you want something more feature rich, look at Paratest (with its shard functionality) or Shipmonk's PHPUnit parallel job balancer. That said, if all you need is to split a PHPUnit suite over a few parallel CI jobs, Test Splitter does exactly that — and nothing else.

Test Splitter is available on GitHub and Packagist.