2

Automated software testing professionals often make a distinction between various kinds of test doubles such as Mocks, Stubs and Shim/Fakes.

In fact, in the article Mocks Aren't Stubs Martin Fowler describes clearly the difference between the types of test doubles.

I am left wondering what is the usefulness of such a differentiation.

My objective is to avoid calling real dependencies when I create Unit tests, does it make difference if I know if I am using a mock or a stub?

  • 4
    Read the article again. Using a fake is usually a lot cleaner than using a mock, because it’ll implement an interface, so you don’t need to write which method should be called in the test. So whenever you’re in the mood of refactoring, you don’t have to change every single test using a mock and declaring the name of the method you’re calling in the implementation of the SUT. You only need to change the name of the method in the fake class. The difference is night and day really. – Steve Chamaillard Sep 23 '19 at 13:25
  • 1
    @SteveChamaillard there's definitely a difference between using a "fake" and using a "mock" - but does it really matter what we call it or can we just keep using "mock" for everything? – Jacob Raihle Sep 23 '19 at 13:31
  • 2
    It’s all about precision when you need it. I can live here with a single English word for snow, whereas people in other more extreme regions use 50 different words (washingtonpost.com/national/health-science/…). Because in their area it really matters – Christophe Sep 23 '19 at 14:11
  • 2
  • 2
    I'd say it's the difference between talking about lists or linked lists. It's context dependent when you might need additional precision in your explanations. – Kayaman Sep 24 '19 at 6:09
4

Whether you are using mocks or stubs does not really make that big of a difference. But what does make a huge difference is using mocks or stubs on one hand, versus using fakes on the other hand.

Mocks/stubs and Fakes (using Fowler's terminology) make different amounts of assumptions about the world, and subsequently the choice of whether to use mocks/stubs or fakes has a real impact on what kind of testing you are doing:

  • are you doing genuine, traditional, bona fide "unit testing", or
  • are you taking shortcuts and mixing your unit testing with integration testing?

More importantly:

  • are you testing against the interface? or
  • are you testing against the implementation?

Mocks usually assume a lot: They assume that specific methods will be invoked, sometimes in a specific order, usually with very specific arguments, and they return very specific predetermined results in each call, which represent another whole new level of assumptions: they are the results that some programmer assumes that the real module would have returned for the given parameters and in its presumed state.

Stubs make somewhat fewer assumptions about the ways in which they are invoked, but they still assume a lot, both in terms of how they will be invoked, and in terms of how the real module would have responded. That's because stubs, just like mocks, are only built to respond to the specific usage pattern that is expected from the unit-under-test, when exercised by the specific test. Essentially, the use of stubs is equivalent to the use of mocks, their only difference being that stubs are usually hand-crafted, so even if you wanted to code more assumptions it would be a lot of work to do so, while mocks are usually created using some mocking framework which makes it easy to specify assumptions, so you are likely to specify more of them.

Fakes, on the other hand, tend to make as few assumptions as possible, and instead they try to offer a set of functionality that is as close as possible to the real thing. The ideal fake behaves in a way which is indistinguishable from the original, from the point of view of code which is exercising its public interface. (The differences are in their inner workings, and of course in what other subsystems they may or may not invoke in order to do their job.) As such, fakes usually do not depend on any particular usage pattern from any unit-under-test, exercised by any test.

From the above it should be clear that when you are using mocks or stubs you are making excessive amounts of assumptions about the inner workings of the unit under test, while when you are using fakes you are making no such assumptions: you don't care exactly how your unit-under-test is invoking your fake object, all you want to see whether the end result of their interaction is correct.

This in turn means that:

  • When you are using mocks or stubs you are doing traditional unit testing "by the book", and you are totally disregarding the advice which says "test against the interface, not against the implementation".

  • When you are using fakes you are not really doing unit testing "by the book", you are mixing it a bit with integration testing, (*) but you can in fact stick to testing against the interface instead of the implementation.

These are the facts, and you can use them to make your own educated choices. If you want my opinion, fakes are a far superior choice to mocks and stubs, because testing against the implementation is not a wise thing to be doing, whereas doing something by the book when there is no objective merit in doing so is just cargo-cult programming.


(*) I am saying "mixing it a bit with integration testing" in the sense that you are testing in integration with the fake, and you are deviating from the rule of unit testing which requires exercising your subsystem-under-test in complete isolation from its environment. With fakes, you do not anymore have complete control over every single detail of the interaction between your subsystem-under-test and its dependencies; you let the subsystem-under-test invoke whatever methods it needs on the fake, while the fake responds as faithfully to the original as possible. If the subsystem-under-test invokes a method on the fake that you did not expect to be invoked, or with parameter values that you did not expect, you will not necessarily know from this type of testing. This is exactly what happens in integration testing. And it is okay, because all you care about in integration testing is correctness of the end result of the interaction between your subsystem-under-test and its dependencies. In this case it just so happens that some or all of the dependencies are fakes.

  • Why are you saying that using Fakes your are mixing a bit with integration testing?. For me are two different things. You are not testing the integration with the 'real dependency'. Can you explain me this point in more detail? – Leonardo Mangano Jun 22 '20 at 20:45
  • @LeonardoMangano I added an explanation. – Mike Nakis Jun 23 '20 at 8:19
  • I guess I need to dig more deep in these concepts, thanks for the answer – Leonardo Mangano Jun 24 '20 at 0:55

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

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