🔥 Hot Take 🔥
- Any library which provides an interface to a dependent resource should also provide a mock of the interface.
- As a library evolves, so too should its mocks.
- These mocks should handle most standard cases, and attempt to avoid solving edge cases.
- Edge cases should be handled by a mocking tool, or by the consumer creating their own custom mock.
- Having the library be opinionated about mocks helps keep testing and usage more consistent across consumers
Testing can be difficult to do. Mainly it can be difficult to find the effort to write a test for a new feature you’ve added which has coupling with necessary dependencies. Worse, as a system evolves the number of dependencies often grows and their interfaces change. To have a solid basis of social/solitary unit testing effective mocking of these resources is essential.
There are libraries which are able to generate methods for interfaces of dependent resources. I have a couple of gripes with these.
Mainly...
...they can often be overly complex and have an API surface area beyond any need we would have. I don’t want to count the number of times when talking with another engineer about how to test something that a bike shedding session is started scouring the mock library api. Often the problem with these libraries is that they are trying to address every use case their consumer might encounter.
I will admit that these mocks can unblock writing tests in a system that is unknowable and tightly coupled. They’re extremely useful in these scenarios when we just want tests. However, most of the time it’s best to detangle the coupling and understand the system better. After all, tests are giving us assurance that our features work, don’t we want the assurance of understanding our system and potential side effects of features? Yes, we do.
An Alternative
Any library which provides interface to a dependent resource could provide an opinionated mocking of the interface. Usage of this mocking would still requires understand of the system and any unhandled effects that a generated mock could not. Instead of interacting with a mock where you must provide the response, you can interact with the resource in your test as you would in code.
An additional benefit is a single source of truth for mock. Given a lib with semantic versioning, the mock can be tied to the version of the interface. A downside to generated mocks is that the consumer usually generates their mocks based off the dependencies interfaces and stores them locally. If a generated mock is sufficient for a dependency, the maintainer could determine that, generate and provide a single source of mocking truth for consumers.
To see more hip-shot thoughts on this, read the hot-takes at the top.
I think I’ve said everything I want on this topic.
What is your experience using generated mocks vs mocks provided by a library?
Or perhaps, what has your experience been writing mocks vs generating mocks?
Top comments (0)