levelmax World 4 Testing Properly
  1. 1
  2. 2
  3. 3
  4. 4
  5. 5
  6. B
L
Level 4.B ~30 min Target: PHPStan max

Boss: test a legacy service

InvoiceTotal was ported line for line from the old billing system in 2019. Finance reconciles against its totals every month. It has one test, which checks the total is more than £10. Next sprint, someone wants to refactor it.

Before then, it needs characterisation tests: tests that record what the code does today, so a refactor that changes any total goes red.

Record what it does, not what it should do

A characterisation test isn't a spec. You don't decide the right answer and assert it. You run the code, write down what it gives, and assert that. If it does something odd, the test pins the odd thing and its name says so:

yield 'quirk: an empty invoice abroad still pays the surcharge' => [[], 'DE', null, 250];

Then raise the quirk with whoever owns the behaviour. Fixing it might be right, but it's a change to the totals finance sees, and it's a separate decision, made on purpose, with its own commit. While you're pinning, the code is right by definition.

Your checklist

Level Ask of your tests
4.1 What's worth testing Does every test check a total? Nothing that only proves a type.
4.2 Data providers Is every decision in of() covered on both sides, as named cases?
4.3 Fakes over mocks Is TaxRates a small fake with different rates per country, not a stub returning one number?
4.4 Time, randomness and I/O Nothing here reads the clock. Check that before you trust a legacy test.
4.5 Mutation testing Would each planted bug fail an exact assertSame()?

Start by reading of() and listing every if. Each one is at least two cases.

CHALLENGE

InvoiceTotal (read only) was ported line for line from the old billing system. Finance reconciles against its totals every month, and it has one test that checks the total is more than £10. Before anyone refactors it, it needs tests that pin down exactly what it does.

In tests/InvoiceTotalTest.php, write characterisation tests until they catch all seven planted bugs. Record what the code does, including anything that looks wrong. Fixing it is a separate decision.

Running on PHP 8.3…

Run the tests, run PHPStan, or submit for both. Ctrl/⌘ + Enter submits from the editor.