Is using mocks in the following way a bad idea:

  1. writing tests where mocks expect certain calls from the subject under test
  2. Or even just writing mocks that return values to the subject under test if/when requested

Reason for my doubts: It ties down the SUT to an implementation, since the tests would need to change when the SUT's implementation changes, even if its required behaviour is the same.

I see one alternative: Just pass the SUT the actual collaborating objects it will be working with. So as the implementations change of both, the tests will need fewer changes and still be valid.

Of course there will be times when to thoroughly test an object, it needs to be fed contrived information from the objects it depends on, in which case mocking frameworks might make sense, but still often might be overkill compared to writing test objects that extend an interface common with those collaborators.

Am I missing a benefit of using mocks? Is my above reasoning sound, or should I be using mocks in the above situations for a reason I haven't understood?

  • 1. is the only reason why the mocks are created – BЈовић Oct 13 '15 at 7:40

You are right that tests would need to change when the implementation changes. However, the value of your tests is that because the behaviour of the system under test does not change your tests will still be valid. What your class does should not change, but how your class does it can. Your tests will help you when you need to rewrite (a part of) the class.

Also, 'writing test objects that extend an interface common with those collaborators' IS mocking (or stubbing). Just because you are not using a mocking framework does not mean it's not mocking.

As a side note: I've seen implementations change because we wanted to optimize them (extract common code, reduce complexity, etc...) but I haven't come across many situations where a changing requirement causes heaps of test code to become obsolete, but a class and its output remains relevant. Think of the O in SOLID: open for extension, closed for modification. Adding functionality or behaviour doesn't mean you should always rip out the internals of the code and completely rewrite it.

| improve this answer | |

I can answer your questions concisely: No and no.

One of the tenets of good tests is that they should be repeatable (FIRST principles) so having a mock that behaves in a consistent way is not only desirable, but necessary.

There are unit testing frameworks (such as NUnit) that provide a way to produce N calls to methods with random values but I would suggest that these are used sparingly with tests at the limits of the known values (or with other pertinent business rules) being preferred instead.

There is of course a place for such tests - especially when the range of values is vast, but this should be conducted outside the usual unit test run sphere (test runs should be fast) - perhaps as an integration or soak test.

| improve this answer | |

Perhaps this is why giving mocks with expectations isn't bad:

  • When the sole purpose of the SUT Foo is to manipulate other objects (X and Y) in a certain way.
  • Writing mocks with expectations within a test serves as documentation of how the SUT is expected to manipulate the objects it calls.

If you were to write a test for yet another subject Bar which requires the above SUT, Foo, and you had to set up the SUT with its collaborators, X and Y, you may not care what Foo does with X and Y them since you are only trying to test Bar, but you may still need to know what Foo is doing with X and Y in order to give Bar the context it needs to be testable.

Although that would start being a very messy test, obfuscating the purpose, which is to test Bar. In which case, Foo should probably be mocked/stubbed/faked/dummied and passed to Bar.

| improve this answer | |
  • 1
    Self-answered questions are encouraged within StackExchange, but they are not meant as a means to encourage discussion. – user53019 Oct 13 '15 at 13:55
  • @GlenH7 There's a difference between viewpoints and a discussion. It just happened that my answer manifested from further thought about my problem/question and any opposing reasoning to my question or alternatives to my answer would not constitute discussion but I am convinced simply observation of one of a limited set of common patterns – CL22 Oct 14 '15 at 23:01

Not the answer you're looking for? Browse other questions tagged or ask your own question.