A few weeks ago I learned an important lesson that I’d like to share: When building unit tests, never use a mock/stub unless it’s absolutely necessary. Let me explain with a little example.
Let’s say you’re working on a large project and you start developing Module A, which uses a MySQL database. To write a unit test for this module, you’re going to need to mock the MySQL queries. I have used sinon for this purpose and it’s worked great by the way. You typically don’t want your unit tests accessing a real-life database server, so using a mock here makes a lot of sense.
Now let’s say you’re adding a new Module B to your project, which uses Module A. As you’re writing the unit tests for this new module, I highly recommend NOT mocking Module A. You should instead continue to only mock the MySQL module as you did when testing Module A.
The reason I recommend this is that every time you mock an interface, you’re usually replacing the real code with a very simple imitation of it. You might have the mocked Module A always return success or failure, depending on what you’re trying to test in Module B. However, you’re very likely to miss out on a lot of detail. It’s highly unlikely that the mock will validate input formats and data structures for example.
By over-using mocks, you end up accumulating technical debt in the form of bugs and implementation errors that will only show up in E2E/integration testing. Debugging in unit tests is typically faster and easier than in an integration environment, so we definitely want to catch as many bugs in the unit test as possible. Unit tests will never catch all the bugs, but minimizing the use of mocks will help you catch more bugs at that stage.