Thoughts on Mocking
I tend to avoid testing interaction among components within the same runtime. Instead I learn towards writing either an API test or a unit test that injects instances of dependencies. In doing so I’ve found that the tests I write more closely align with the behavior users actually care about.
Why?
The rationale I often hear behind mocking is that if you test x
, y
, and z
well in isolation and test that x
is calling y
which is calling z
in a particular way that you’ve in essence tested the whole. Think transitive relation.
I tend to disagree with this and find that this method of testing is often pretty brittle. I'm probably in the minority here. The problem with this is that you don't really know that all the pieces work together to form the behavior you expect. Another problem is that testing in this way lends itself to regression bugs accompanying future changes.
When you test in this way, do you find the need to “sanity check” and manually test? If so, this should be a red flag. What if the wiring up of those components is jacked up in some way? What if z
has in fact not been tested the exact same way y
is calling it? Will a test discover the issue before a user? What gives you the confidence you need in order to sleep at night?
Another aspect to consider is refactoring and new, intersecting features. What will facilitate new developers being comfortable making changes? What if the team wants to “majorly” refactor some internals? Does the testing exist to give the team confidence that behavior hasn’t changed?
By the way, this doesn’t necessarily eliminate the value of writing unit tests. In other words, just writing integration tests is probably a bad idea. Think of piping together a series of unix programs to accomplish something novel. You as the consumer of those programs expect that each is well tested. The same might be true of a low-level unit (e.g. a function): you want to have confidence that it is working before using it as a piece of something greater. But you also probably want to test that your novel program actually works ;-).
To summarize, I tend to replace unit tests that verify interaction with integration tests. Specifically either Owin.Testing.TestServer-backed API tests or unit tests that inject instances of dependencies (vs mocks). Here are some more links that have influenced my views on testing: