Library / SDK
infection/infection avatar
infection/infection

Infection: mutation testing that finds the assertions that never fail

PHP Mutation Testing library

2,254 stars195 forksPHPBSD-3-Clause

At a glance

What is it?
A PHP framework that changes your source code, re-runs your suite and counts how many of those changes the suite noticed, which is the only honest way to measure a coverage number.
Who is it for?
Infection is worth the cost on the code paths where a wrong answer is expensive, and it earns its keep because its output is a list of surviving mutants rather than a single percentage.
Can I use it commercially?
Yes. BSD-3-Clause is a permissive licence: you can use, modify and sell software built on it, as long as you keep its copyright and licence notices.
Is it still maintained?
Yes. The repository last received commits 1 day ago.
What is it written in?
Mainly PHP, according to GitHub's language statistics.

Answers come from the project's GitHub data, last synced on October 7, 2026, and from our analysis. They are not legal advice.

Editorial analysis

Why coverage is the wrong number

Code coverage answers a question about execution: did this line run at some point during the test suite? Mutation testing asks a different question: if this line behaved differently, would a test notice?

The way a mutation testing tool answers that is mechanical. It takes a covered piece of source, applies a small semantic change to it, and re-runs the suite against the modified code. If a test fails, the mutation was caught, and the test suite has real evidence about that behaviour. If every test still passes, the mutant survives, which means the code has changed in a way nothing noticed. The Mutation Score Index, the MSI, is the proportion of mutants killed.

The repository describes Infection as a PHP mutation testing framework, with topics covering AST, coverage, mutants and mutation analysis. The AST topic is the load-bearing one: to change an operator or a boundary value without changing the shape of the program, the tool has to parse the source rather than do text substitution. That is why this is a static-analysis-adjacent project and not a runtime fuzzer.

The practical value is that surviving mutants point at missing assertions directly. A line at 100 percent coverage with a surviving mutant tells you a test executed that line and still did not check what it computed. No other tool reports that.

A PHAR, a config file and four PHP versions

The project's own configuration sits at the repository root as `infection.json5`, which is a JSON5 file, so comments are allowed in a config format that is otherwise JSON. There is also `phpunit.xml.dist` for the test configuration and a separate `phpunit_autoreview.xml`, which is a PHPUnit run against the project's own code.

Distribution is as a PHAR. `box.json.dist` and `scoper.inc.php` configure the PHAR build, `dist/` is where the artifact lands, and the Makefile defines `INFECTION=./dist/infection.phar`. Box is the same tool the project credits for Humbug, and scoping the build is what lets a single PHAR carry its dependencies.

The supported runtime floor is on a badge rather than in prose: PHP 8.3.0 and above. The development matrix is more revealing, because `docker-compose.yml` defines four services named for the PHP version they test:

code
  php85:
    build:
      context: devTools
      args:
        PHP_VERSION: '8.5'
        XDEBUG_VERSION: '3.5.1'
    volumes:
      - .:/opt/infection

The siblings cover 8.3 with Xdebug 3.4.1, 8.4 with 3.4.0, 8.5 with 3.5.1, and 8.6 release candidate with a matching alpha Xdebug. A tool that mutates code and inspects coverage traces has to be correct on every version it claims, because a coverage backend mismatch produces results that are wrong rather than absent.

The same compose file runs zizmor, pinned to 1.30.1, against `.github` with a minimum severity of low. That is a GitHub Actions security scanner running on the project's own workflows, which tells you the team treats their CI as production infrastructure.

The test toolchain in the Makefile

The Makefile is the clearest inventory of the project's tooling, and every tool is pinned to a version or a path rather than assumed.

Static analysis has three separate entries: `PHPSTAN=./vendor/bin/phpstan`, `MAGO=./vendor/bin/mago`, and `RECTOR=./vendor/bin/rector`. Rector is configured by `rector.php` and mago by `mago.toml`, so two distinct static analysis tools run alongside PHPStan. Style is handled by PHP-CS-Fixer, pinned as a downloaded phar at version v3.92.5 and configured by `.php-cs-fixer.php`.

There is a `COLLISION_DETECTOR=./vendor/bin/detect-collisions`, which is the tool that finds class or function name collisions introduced by scoping a PHAR. Its presence is a direct consequence of the single-file distribution model.

Tests run through `vendor/phpunit/phpunit/phpunit`, with `--no-progress` appended when `CI` is set, and `vendor/bin/paratest` is available for parallel execution. Benchmarks are configured through `phpbench.json` with aggregate and bar chart iteration reporting, and the Makefile defines named benchmark source sets for the mutation generator, the git diff source and the tracing coverage directory.

Parallelism and locking are handled explicitly: `FLOCK=./devTools/flock` is passed into every `docker compose run`, so concurrent container invocations serialise on a file lock rather than colliding over the working directory. The Makefile also sets `--warn-undefined-variables` and `--no-builtin-rules`, both of which catch Makefile mistakes that would otherwise pass silently.

That combination is a lot of machinery, but each piece is there because the project ships a PHAR that rewrites other people's code and must behave identically across PHP versions and on Windows.

Recent releases are an architecture refactor in progress

The 0.35.x releases read differently from a typical feature release stream, and the reason is visible in the pull request titles.

Version 0.35.5, published 2026-09-27, has one user-facing fix: a null array key deprecation in the Stryker HTML report, from the same family of reporters Infection uses for its Mutation Score Index badge. The rest is internal. A PHPStan rule was added to capture deprecated usages in the project's own test framework, a PHP-CS-Fixer rule enforces semicolon position, unused abstractions were removed from the test framework, and, most tellingly, direct file access was replaced with a FileSystem abstraction across several pull requests followed by one making all FileSystem usage explicit. Test framework operations were routed through a new contract.

Version 0.35.4, published 2026-09-02, fixed the test framework finder and removed the duration test orders when the test run history is disabled. Version 0.35.3, published 2026-08-27, fixed GitDiffSourceLineMatcher compatibility with Windows, which is the kind of bug that only appears on the platform with the least CI coverage relative to its user share, and included a performance change to stop retaining every Mutation object until the end of a run.

So the 0.35 line is spending its effort on making the internals testable and portable rather than on adding mutators. Two structural files support that reading: an `adr/` directory for architecture decision records, and an `AGENTS.md` for automated contributors. The repository has 2,244 stars, 192 forks and 220 open issues, is BSD-3-Clause licensed, and the last push was on 2026-09-27.

Lineage, sponsors and the playground

The README's credits section is short and explains the project's design heritage. Infection is described as highly inspired by Humbug, a mutation testing library by Pádraic Brady, and the README notes that Humbug has since been discontinued in favour of Infection. So this is a successor rather than an original entry, and the credit is explicit about it.

The sponsor list mixes companies of quite different kinds. TestMuAI appears as a company sponsor alongside individual accounts, Enrise is listed as a company, and JetBrains is credited specifically with free licenses for core developers, which for a PHP project means PHPStorm. Sentry and Tideways are sponsors too, and both are error monitoring services, which is a reasonable fit for a tool that often runs in the same pipeline as test and monitoring infrastructure.

Two links are worth trying before installing anything. There is a Playground at infection-php.dev described as a way to try the tool right in the browser, which removes the setup cost of evaluating a mutation testing framework entirely. And there is an MSI badge in the README that pulls from the Stryker mutator badge service, so the project's own mutation score is tracked the same way other projects track build status.

Community links are on Twitter and Mastodon under the same handle, `@infection_php`, plus a Discord server. The README is otherwise a pointer document: it says to read the documentation at infection.github.io and links a contribution guide in `.github/CONTRIBUTING.md`. Configuration options, the list of mutators and the threshold settings live in that documentation, not in the repository.

Editorial conclusion

Infection is worth the cost on the code paths where a wrong answer is expensive, and it earns its keep because its output is a list of surviving mutants rather than a single percentage. The details that decide whether it is usable for you are in the repository rather than the README: the supported PHP versions run from 8.3 upward through a 3.6 release candidate, the release train is currently adding architectural structure rather than features, and there is a browser playground at infection-php.dev for evaluating the idea without installing anything. Start with one directory or one pull request rather than the whole codebase, since the run time scales with how much source a test suite is willing to cover, and treat the Mutation Score Index badge as a trend to watch rather than a target to hit. It is BSD-3-Clause licensed, at version 0.35.5 with a last push on 2026-09-27.

Frequently asked questions

What does Infection do differently from running a code coverage report?

Coverage reports whether a line executed during your test suite. Infection mutates covered source code, for example changing an operator, and re-runs the suite. If a test fails, the mutation was caught. If every test still passes, the mutant survived, which means nothing in the suite checks the behaviour on that line even though it runs it.

What PHP version does Infection require?

PHP 8.3.0 and above, according to the minimum version badge in the README. The development matrix in docker-compose.yml is broader still, covering 8.3, 8.4, 8.5 and an 8.6 release candidate, each paired with a specific Xdebug version because coverage traces come from Xdebug.

How is Infection distributed?

As a PHAR in `dist/`, built with Box. `box.json.dist` and `scoper.inc.php` configure the build and the scoping, and the Makefile points at `./dist/infection.phar`. A collision detector runs in the toolchain because scoping a PHAR into a single file can introduce class name collisions.

What is the relationship between Infection and Humbug?

Infection replaces it. The README states the project is highly inspired by Humbug, a mutation testing library by Pádraic Brady, and that Humbug has been discontinued in favour of Infection. The Box PHAR tooling used to build Infection comes from the same Humbug project.

How do I try Infection without installing it?

There is a Playground at infection-php.dev that the README describes as a way to try it right in the browser. That is the cheapest way to see whether mutation testing fits your workflow before wiring it into a build, and it avoids the version and Xdebug constraints that a local install imposes.

Official sources

  1. infection/infection on GitHub
  2. License: BSD-3-Clause
  3. Project website
  4. README
  5. Releases
Add this badge to your README

If you maintain this project, the badge below links readers to this analysis and shows its maintenance status from the daily GitHub snapshot. Paste the markdown into your README; add ?metric=license or ?metric=stars to the image URL for a different field.

Add this badge to your README

markdown
[![Hysen Labs](https://hysenlabs.com/badge/infection-infection.svg)](https://hysenlabs.com/projects/infection-infection)