Their tests only check that the code calls its mocks the way the author expected. They don't check that the code works with the real database and APIs. Each mock returns whatever the test told it to return. So these bugs all pass the tests:
- a wrong SQL query
- a missing migration
- a unique constraint that the data breaks
- a transaction that never commits
- a third-party API that changed its response
The fix is to move confidence to the boundaries. Add:
- integration tests that run repositories and queries against a real Postgres in Testcontainers (a library that starts real services in Docker for your tests)
- API tests that go through the real Nest pipeline, using supertest
- contract tests, or realistic recorded responses, for third-party APIs
Then delete or simplify unit tests that only repeat the implementation, such as "calls repo.save with X". Keep unit tests where there is real logic to check. In them, assert outcomes (what the code returns or changes), not calls.
- Mocks contain the author's assumptions, so bugs at the boundaries still pass.
- Add integration tests that run against a real database.
- Add API tests through the real HTTP pipeline, and contract tests for other services.
- Remove tests that only mirror the implementation.