Writing a good unit test and reporting a bug in a way the team can act on are the same discipline applied at two different moments: communicating clearly what happened, and what should have happened.

This is a short guide to structuring a test, choosing test doubles, and reporting a reproducible bug.

1. Start with a clear unit test

A direct summary of PHPUnit best practices:

  1. Be descriptive about what you’re testing.
  2. Be explicit about what you’re testing.
  3. Use the most specific assertion possible — assertCount(3, $items) instead of assertTrue(count($items) === 3).
  4. Decouple test code from test data. If the data changes, the test shouldn’t have to change with it.
  5. Use a configuration file instead of scattering manual setup across tests.
  6. Write real unit tests — use stubs and mocks when it makes sense, not as an automatic reflex.

2. Structure the test with the Triple A pattern

  • Arrange: set up the test — variables, mocks, spies.
  • Act: run the thing being tested.
  • Assert: check that the result matches what’s expected.

Visually separating these three steps in the code — even with just a blank line between them — already makes the test easier to read six months later.

3. Choose between a stub and a mock

  • Stub: a simple fake object that just makes sure the test runs without breaking on external dependencies.
  • Mock: a smarter stub — you verify the test passed through it, checking that it was called the right way.

Confusing the two is common, and the practical effect is using a mock where a stub would already do the job — leaving the test more coupled to the implementation than it needs to be.

4. Report the bug with enough context

  • Problem description: objective and clear, stating whether it’s always reproducible or intermittent. Example: “On the login screen, typing the password doesn’t mask the characters.”
  • Severity: does the bug block you from continuing to test? High. If not, medium or low, depending on context.
  • Steps to reproduce: step by step, don’t skip any.
  • Environment and version: where it happened — staging, dev, production — and which version.
  • Platform: browser, operating system, specific app.
  • Evidence: screenshot, video, log.

The same principle, two moments

A well-designed test — AAA applied with the right test doubles — is already halfway to a bug, when it appears, being easy to report and reproduce. That’s not a coincidence: both require the same clarity about what’s expected, what was observed, and exactly where the difference showed up.