An in-memory repository passing every test, and a real one that had gained a behaviour the fake did not have.
// the contract test both must pass
abstract class OrderRepositoryContract extends TestCase
{
abstract protected function repository(): OrderRepository;
public function testSaveIsIdempotentForTheSameId(): void { /* ... */ }
public function testFindReturnsNullForAnUnknownId(): void { /* ... */ }
public function testSaveRejectsAnOrderWithNoLines(): void { /* ... */ }
}
// the third test was added when the database gained a
// CHECK constraint. the fake did not enforce it and
// twelve unit tests had been relying on that.
A constraint added to the database is a behaviour change that the fake does not inherit, and the contract test is the only thing that surfaces it. Twelve tests constructing an invalid order and passing is the cost of a fake that is more permissive than reality — and the fix in each case was a fixture that was wrong rather than code that was.