Hacker News new | ask | show | jobs
by spawarotti 1463 days ago
This rule is also recommended by section 9.2.4. "Only mock types that you own" of 2020 book by Vladimir Khorikov: "Unit Testing Principles, Practices, and Patterns".

Worth noting is that book also says in 9.2.1: "Mocks are for integration tests only". I agree.

In my opinion this book is the best comprehensive take on testing I ever encountered.

2 comments

> "Mocks are for integration tests only"

as opposed to what unit tests? how are you suppose to "unit test" that you properly increment a varibale before inserting into the DB without mocking the DB? I disagree, mocks are for unit tests only. mocks allow you to isolate the unit to be tested.

integration tests is when you start integrating dependencies together. so maybe you have a dummy database like an in-memory db, but you're certainly not mocking it.

system tests is where you would use the actual db.

> how are you suppose to "unit test" that you properly increment a varibale before inserting into the DB without mocking the DB?

You put the logic that increments that variable into a pure function and unit test the input/output pair. Because it is now decoupled from the database, you don't have to deal with it.

> mocks allow you to isolate the unit to be tested.

You achieve isolation instead by refactoring to a "pure functional core and mutable outer-shell" architecture. Above I gave one example of refactoring to functional core. In the cases where you still need to deal with external dependencies in unit tests, you use in-memory implementations (aka simulators) instead of mocks.

Basically there are two subtypes of unit tests - small focused unit tests, testing input/output pairs of purely functional code, and "bigger" unit tests, that check how bigger units of internal business logic collaborate together. They use the in-memory simulators to ensure the tests maintain all the properties of a good unit test: runs fast, doesn't interfere with other tests, requires zero setup, is not flaky and makes zero assumptions about the environment.

So, overall - no mocks for unit testing.

> mocks are for unit tests only.

I do think the opposite is true, with very few exceptions. Mocking in unit testing is an anti-pattern leading to brittle tests with negative value - the cost of maintaining them is way higher than any benefit they provide. Too many false positives, too little true positives, too much rework needed when code changed but no bug was introduced, too unreadable code.

> integration tests is when you start integrating dependencies together. so maybe you have a dummy database like an in-memory db, but you're certainly not mocking it.

This is the only case mocking makes sense. In integration testing you want to test integration with one external endpoint. Hence you mock or simulate all the others. In unit testing there is no need for mocking as explained above. In system (end-to-end) testing there is no need for mocking because we test how everything integrates together.

Naturally, there is way more nuance to the simplified statements I made above. The book elaborates on that. There is also an article by the same author about it: https://enterprisecraftsmanship.com/posts/when-to-mock/

Why do you care what you insert into the DB? Your test for a Put method should validate the return from the corresponding Get.
FWIW I think the database is an integral part of one's service, and should often be included in unit tests (depending on the size of the unit of course).

E.g. if you have CRUDObject and want to test GET and PUT of that...and that is the unit you want to test.. mocking away the DB is (IMO) not as good as including a real database with no data in it (they come in Docker images and making a fresh DB namespace within a running sql server for a single test can be very cheap / cheap enough).

Second the recommendation, great book even if like me you don't care about C#