Writing tests that survive a refactor
A test suite that breaks every time you touch implementation isn't protecting you.
The purpose of a test suite is to give confidence that behavior didn't break — but a suite that fails on every internal refactor, even when behavior is unchanged, trains a team to ignore its own tests. That's a worse outcome than having no tests at all.
Test behavior, not implementation
Tests that assert on internal function calls or private state are tightly coupled to how the code happens to be written today. Tests that assert on observable behavior — given this input, the system produces this output or effect — survive a refactor precisely because they don't care how the answer was reached.
Fewer, better integration tests
A handful of well-chosen integration tests, exercising real code paths end to end, often catch more real bugs and survive more refactors than dozens of narrowly-scoped unit tests mocking every dependency. Both have a place, but the balance matters more than the total count.
Flaky tests are worse than missing ones
A test that fails intermittently for reasons unrelated to the code being tested teaches the team to re-run and ignore failures — which quietly erodes trust in the entire suite, including the tests that are genuinely catching real problems.
- Assert on observable behavior, not internal implementation details.
- A few well-chosen integration tests often outlast many brittle unit tests.
- Fix or delete flaky tests — they erode trust in the whole suite.
The on-call rotation nobody dreads
HAVE A PRODUCT IN MIND?
Tell us what you're building and where you need engineering support.