Unit Testing – Do Mocks Violate the Open/Closed Principle?

mockingopen-closesolidstubunit testing

Some time ago I read, on a Stack Overflow answer that I can't find, a sentence that explained that you should test public APIs, and the author said that you should test interfaces. The author also explained that if a method implementation changed, you shouldn't need to modify the test case, as doing this would break the contract that make sure the system under test works. In other words, a test should fail if the method doesn't work, but not because the implementation changed.

This called to my attention when we talk about mocking. Since mocking relies heavily on expectation calls from system under test's dependencies, mocks are tightly coupled with the implementation rather than the interface.

While researching mock vs stub, several articles agree that stubs should be used instead of mocks, as they don't rely on expectations from dependencies, meaning the test need no knowledge of the underlying system under test implementation.

My questions would be:

  1. Do mocks violate the open/closed principle?
  2. Is there something missing in the argument in favor of stubs on the last paragraph, that make stubs not so great vs mocks?
  3. If so, when would be a good use case to mock and when would be a good use case to use stubs?

Best Answer

  1. I do not see why mocks would violate the open/closed principle. If you could explain to us why you think they might, then we may be able to alleviate your concerns.

  2. The only disadvantage of stubs that I can think of is that they generally require more work to write than mocks, since each one of them is actually an alternative implementation of a dependent interface, so it generally has to provide a complete (or convincingly complete) implementation of the dependent interface. To give you an extreme example, if your subsystem under test invokes an RDBMS, then a mock of the RDBMS would simply respond to specific queries known to be issued by the subsystem under test, yielding predetermined sets of test data. On the other hand, an alternative implementation would be a full-blown in-memory RDBMS, possibly with the extra burden of having to emulate the quirks of the actual client-server RDBMS that you are using on production. (Luckily, we have things like HSQLDB, so we can actually kind of do that, but still, it is a bit messy, especially since it mostly sticks to the SQL standard and does not bother emulating anyone's quirks.)

  3. Good use cases for mocking are when the dependent interface is too complicated to write an alternative implementation for it, or if you are sure you will only write the mock once and never touch it again. In these cases, go ahead and use a quick and dirty mock. Consequently, good use cases for stubs (alternative implementations) is pretty much everything else. Especially if you foresee engaging in a long-term relationship with the subsystem under test, definitely go with an alternative implementation which will be nice and clean, and will require maintenance only in the event that the interface changes, instead of requiring maintenance whenever the interface changes and whenever the implementation of the subsystem under test changes.

P.S. The person you are referring to could have been me, in one of my other testing-related answers here on programmers.stackexchange.com, for example this one.

Related Topic