Frequently Asked Questions

Answers to questions I am asked again and again about PHPUnit, test automation, code coverage, and testing in PHP. Where it helps, an answer links to a fuller article.

Code Coverage

Should I use PCOV or Xdebug to collect code coverage?

Use PCOV when you only need line coverage: it is considerably faster and ideal for CI. Reach for Xdebug when you need branch or path coverage, or when you already run it for step debugging. Enabling both at once rarely makes sense.

Read more in the article: PCOV or Xdebug?

Can I merge code coverage data from several test runs?

Yes. Collect coverage separately for each run, for example when you shard or parallelise your suite, export it in PHP or Cobertura format, and merge the reports afterwards. This gives you one combined figure without forcing every test into a single run.

Read more in the article: Merging code coverage data

My coverage is green but bugs still slip through. What now?

Line coverage only tells you which code was executed, not whether your assertions actually check anything. Path coverage reveals untested combinations of branches, and mutation testing measures whether your tests would even notice a change to the code. Both expose confidence that coverage alone cannot.

Read more in the article: Path Coverage or Mutation Testing?

Test Doubles (Mocks and Stubs)

What should I use instead of withConsecutive()?

withConsecutive() was removed in PHPUnit 10. Replace it with a single willReturnCallback() that inspects the arguments, combined where needed with the invocation matcher returned by $this->exactly() so you can react to each call by its number. It is more verbose but far clearer about what each invocation expects.

Read more in the article: Better than withConsecutive()

When should I use a stub and when a mock?

Use a stub when you only need a collaborator to return canned values so the code under test can run. Use a mock when the interaction itself is what you want to verify. Verifying calls that do not matter couples your tests to the implementation and makes them brittle.

Read more in the article: The Stub/Mock Intervention

Speed and Performance

How can I make my PHPUnit test suite faster?

There are four levels to work through: the test runner configuration, the infrastructure your tests touch, parallelisation, and the design of the tests themselves. The biggest and most lasting gains almost always come from better test design, not from throwing more cores at a slow suite.

Read more in the article: Turbo-Charging Your PHPUnit Suite

How do I find performance problems in PHP?

Measure before you change anything. A profiler shows you where time and memory actually go, which is regularly somewhere other than where you suspected. Guessing and optimising by intuition tends to make the code more complex without making it faster.

Read more in the article: Debugging Performance in PHP

Test Design and Structure

What makes code testable?

Testable code keeps its dependencies explicit and replaceable, separates decisions from side effects, and avoids reaching into global state. When a class asks for what it needs instead of fetching it itself, you can put it under test without elaborate setup.

Read more in the article: What actually makes code testable?

How should I structure my tests?

Mirror the structure of the code under test, give each test one clear reason to fail, and make the arrange, act, and assert phases easy to see. A test you can read in a few seconds is one you will trust and maintain.

Read more in the article: Test Structure Best Practices

How do I test code that talks to a database?

Separate the logic that builds and interprets queries from the code that executes them, so most of your tests need no database at all. For the part that genuinely depends on the database, test against a real instance rather than a mock, because that is where the surprises live.

Read more in the article: Testable Database Interaction

How do I build type-safe collections in PHP?

Wrap an array in a dedicated class that only accepts the type you want, expose the operations you actually need, and let static analysis verify the element type through generics annotations. You gain safety and a clear API instead of passing raw arrays around.

Read more in the article: Type-Safe Collections

What is property-based testing?

Instead of checking individual examples, you state a property that should hold for all valid inputs and let a tool generate many of them, including edge cases you would not think of. When it finds a failure, it shrinks the input to the smallest case that still breaks.

Read more in the article: Property-Based Testing

Security

What is Test-Driven Security?

For almost every vulnerability that reaches production, there is a test which, had it existed, would have prevented it. Test-Driven Security treats known weakness categories as a checklist and uses the testing tools you already have to prove that each class of flaw is absent.

Read more in the article: Test-Driven Security

Can a slow test suite be a security risk?

It can. If your suite is too slow to run often, automated tools and AI agents cannot use it to check their changes either, so vulnerabilities stay hidden longer. What used to be framed purely as a productivity problem is now part of the security conversation.

Read more in the article: Speed as a security feature

Is it safe to install PHPUnit in production?

No. PHPUnit is a development dependency: require it under require-dev and make sure it never ends up in your production deployment or autoloader. Shipping test tooling to production needlessly enlarges your attack surface.

Read more in the article: PHPUnit: A Security Risk?

Training and Consulting

Can Sebastian Bergmann train my team on PHPUnit?

Yes. I offer tailored workshops and training on PHPUnit, test automation, and testable software design, delivered remotely or on site. See the training section for the current topics.

Can you help make an existing, hard-to-test codebase testable?

That is a large part of what I do. Through consulting and coaching I help teams bring legacy code under test and build the habits that keep it that way. The consulting section describes how that works.