testing

  • A build stage that exists only to fail the build

    A stage that runs the analyser and the tests, produces no artefact, and is depended on by the final stage so it cannot be skipped. BuildKit skips any…

  • Attributes instead of annotations, everywhere

    PHPUnit 10 deprecates the docblock forms in favour of attributes, which is a mechanical change across every test file and a real improvement. Attributes are parsed by the…

  • The generic PHP does not have, and the analyser that does

    A collection class that returns mixed, and forty call sites asserting the type by hand. Docblock generics, and where they stop being worth it.

  • PHPUnit 10, and the listeners that no longer exist

    10.0 in February, a configuration file that has accreted since 2014, and a custom TestListener that the new version has no place for.

  • Time in tests, and the clock we injected

    A test that fails between 23:00 and midnight, once a year, and passes on every rerun. PSR-20 standardised this interface in 2022, which is worth adopting for the…

  • Coverage on a directory, not on a percentage

    A global threshold of 80% says nothing about whether the code that matters is tested, and it is satisfied by testing the code that is easy. Different code…

  • An HTTP client faked at the PSR-18 boundary

    Mocking a client library’s own interface couples every test to that library; faking the standard interface does not. Throwing on an unstubbed request is the design decision that…

  • Extracting a module without extracting a service

    A billing module everybody agrees should be separate, a team of four, and 88 classes that reference it. The boundary, drawn in code rather than in conversation.

  • A flaky test quarantine with a deadline attached

    A group of tests excluded from the pipeline “temporarily”, four of them since 2021. A quarantine without an expiry is a delete with extra steps. Adding a date…

  • The effect that ran twice, and the cleanup that fixed it

    Development mode mounting, unmounting and remounting every component is a diagnostic, and the double-fetch it produces is the diagnosis rather than the bug. An effect that cannot survive…