I’m not a “fan” of the way most of the developers community make use of mocks and stubs. In my humble opinion, it’s a bad use of a very useful tool.
With this kind of use some issues arise, like over-mocking and over-stubbing – the overuse of mocks and stubs. Over-mocking makes your tests brittle, which means that they fail when you change the code even if there are no change on the behavior of the component under verification. Over-stubbing makes your tests weak, which means they pass even if they’re unsynchronized with the code, verifying behavior that isn’t real anymore.
Here’s an example of over-mocking:
Note that even “setter” methods are under expectations here. If you make a simple change on the implementation and, for example, one of these methods aren’t called anymore, even if you don’t change the behavior, the test will fail. This will end up happening anyway when you use mocks (that’s why you need integration tests), but you can diminish the bad consequences.
Here’s an example of over-stubbing:
With this approach you can end up with stubs of methods that no longer exists or even of objects that are no longer a dependency.
The best way to avoid this issues is to learn from trying and studying but, if you use Mocha, you can configure it to help prevent over-stubbing through the class Configuration:
In the above examples, when Mocha finds an “improper” use of stubs, it will throw an exception of the type Mocha::StubbingError. This occurs ‘cause we’ve made use of the method prevent. There are three levels of “protection”:
Note: of course, you shouldn’t use this as a solution for problems with over-stubbing. I think this feature is a good help for teams learning to do TDD or migrating from a “isolationist” style to a more traditional one.
Read more:
Mocha::Configuration RDoc