The integration code you hand over needs fewer mocks than you think
Vladimir Khorikov offers a compact rule for what to mock, along with the trade-off that every test suite has to accept.
In brief
- Khorikov allows mocks only for dependencies that other systems can also reach. An application's own database should be tested against a real instance.
- According to one book summary, a good test protects against regressions, resists refactoring, gives fast feedback and is easy to maintain. The first three cannot all be maximised at once.
- The book is for people who already know unit-testing basics. Its examples are in C# but apply to any language.
The question to ask is who else can reach that dependency. If only your application can, don't mock it.
Graphic: FDE Times
Mock only the external dependencies that other systems share. Vladimir Khorikov, author of Unit Testing: Principles, Practices, and Patterns, set out this rule on his blog, Enterprise Craftsmanship, in 2020. If you are an FDE who has just finished a service connecting a customer’s systems to your company’s product, that sentence could change the whole test suite you are about to hand over.
The reason lies in how handovers work. Once you leave the customer site, their engineering team will be the ones changing that integration code. The test suite is the only thing that tells them what they have just broken. A suite full of mocks, which turns red on every refactor even when there is no bug, will soon be switched off. At that point the tests might as well not exist.
Whether to mock depends on who shares the dependency
Khorikov divides out-of-process dependencies into two kinds. A managed dependency is reachable only through your application, such as the service’s own database. An unmanaged dependency is one that other applications can also reach. From this he derives the rule: use real instances for managed dependencies, and mock only unmanaged ones.
Picture a service you have built for a distribution company. It receives orders, stores them in its own Postgres database, then pushes them to the API of an ERP system that the customer’s accounting and warehouse teams both read.
Postgres is managed, because nothing outside your service touches it. The ERP is unmanaged, because the calls you send to it form a contract that other systems depend on as well.
Applied to this example, the tests run against a real Postgres and mock the ERP at the boundary, checking that the outgoing requests are correct. Now suppose that a few months later the customer’s team renames a column in a migration.
If you had mocked the database, the tests stay green while production breaks. If they run against a real Postgres, they go red straight away in CI. Mocking the ERP, on the other hand, still makes sense: the tests only need to prove that the service keeps its contract with the outside world.
No test suite gets all three at once
The next question is how to judge whether a test is good. According to one set of notes summarising the book, Khorikov sets out four pillars: protection against regressions, resistance to refactoring, fast feedback and maintainability. The crux is that the first three are mutually exclusive. You can pick only two of the three, a trade-off similar to the CAP theorem.
Back to the order service. An end-to-end test that calls a real ERP sandbox catches many bugs and does not break when you restructure the code inside, but it is slow. A small test that mocks everything runs very fast, but it is tied to implementation details and breaks the moment you split a function. The second kind is the one the customer’s team will hate most.
Once you understand this trade-off, you stop looking for a single “right” kind of test. For the order service, a sensible split is many fast tests for pure business logic, plus a small number of integration tests running against a real database.
In the book’s table of contents, Manning lists using integration tests to check the system as a whole, alongside avoiding anti-patterns and refactoring tests together with production code.
Who should read it, and in what order
Manning published the book in January 2020; it runs to 304 pages. On his own site, Khorikov calls it a complete guide to unit testing and argues that programming rules should be derived from first principles.
Manning makes clear that the book is written for people who already know the basics of unit testing. If you have never written a test, learn a framework first and come back later. The examples are in C#, but the publisher says they apply to any language.
If your time is chopped up by customer schedules, try this order. Start with the blog post “When to Mock”, which takes one evening.
Then read the section of the book on the four pillars, since those are the criteria you will use to grade each test. Finally, read the sections on mocks and integration tests, with the code you are writing open alongside.
Manning’s promise is to help you improve an existing test suite with modern practices, and that promise matches an FDE’s reality. You rarely get to write tests from scratch. More often you inherit a customer repo that already has slow, brittle tests with mocks everywhere.
Turning the book into an edge in interviews
Most candidates write a single line on their CV along the lines of “wrote unit tests”. You can be more specific: integration tests that run against a real database, mocks placed only at API boundaries shared with other systems, and a suite that stays stable when the customer’s team refactors after handover.
That line shows a hiring manager that you understand handovers, not just syntax.
In an interview, if you are asked about a testing strategy for an integration system, answer in terms of trade-offs rather than coverage percentages. Say which two of the three pillars you choose for each layer of tests, and why. That is exactly the first-principles thinking Khorikov champions.
When you leave the site, your code stays behind. The test suite will answer, on your behalf, the questions the customer’s team has not yet thought to ask.
Was this article useful?
Thanks for the feedback!