Mocks Aren't Stubs (2007)
martinfowler.com
martinfowler.com
If you’re working with technical people who don’t care about technical details then that’s probably not a good sign!
When would you recommend this practice?
And which of the three would you recommend for what?
With that out of the way, I would recommend using a test double in exactly one kind of situation: When it's genuinely awkward to use the real thing. Concrete examples include talking to a third-party API, testing for error conditions that are difficult or impossible to reliably organically produce, and when the real dependency hasn't actually been implemented yet.
As for the different kinds of test doubles, Fowler has a concise overview at https://martinfowler.com/bliki/TestDouble.html that is just about the clearest explanation I've seen of the different kinds and what they're used for.
THANK YOU.
I'm actually pretty staunchly anti-mocking (and anything similar). I think too many developers start thinking of testing as the goal rather than as the means. What this means to me is I don't care if it's technically an integration test vs a unit test, I care that it tests _REALITY_.
There are times when the isolation given by mocking can be useful, but I submit it's useful far far less often than many claim. And your examples are a good use as well.
But imo trying to mock everything is mostly mental masturbation only with long-term maintenance costs.
I start out with a small & simple fake for something as I'm working on the layer above it, then keep flushing it out as I move on to higher and higher layers.
In the end I have a suite of completely customizable fakes for all of my external dependencies that I can tweak to my every need.
I am curious to know if you ran into similar problem, if you did how you managed to overcome it?
I do see fakes as having overlapping purpose with stubs, though. But, like the title of the article says, mocks aren't stubs.
Poorly named libs (e.g. mockito) just exacerbate this problem.
The way I see it mocks are the all encompassing tool here. With mocks you can both stub behaviors and, if you want, verify behaviors.
And in reality every mock needs to act as a stub, e.g. a mocked method returning a preset value. So, it seems natural that "mocking" as more encompassing concept is what is used in library names. If people end up using those to mostly create stubs instead of mocks so what?
My experience so far has been that people naturally flock to a solution for testing that is flexible and lets them quickly cover the boundaries of the code they are testing. If people want to check if their code calls a method x times but are not interested in what that method does for the test, they use mocks. If they do they use "the real thing" or a fake on which they can validate state later. And if they just need a method to return something and don't care about whether it's called or how often they use a stub.
I feel that often when you stub you can also go ahead and add code to verify some behaviors (mock) to get some extra coverage. I don't know I just don't think it's bad to mix and match if it gets you to more things tested.
Nothing wrong with mocks of course, sometimes they are absolutely required. I just favor isolation using stubs, and using mocks sparingly and only when absolutely needed.
> ...in reality every mock needs to act as a stub I disagree. In fact a collaborator method call that doesn't return a value is a great candidate for mocking. Conversely, a collaborator that does return a value can usually be stubbed.
> ...when you stub you can also go ahead and add code to verify some behaviors (mock) to get some extra coverage Entirely dependent on context of course, but to generalize, this feels risky. In many cases adding extra coverage via mocks might be making tests more brittle, for little to no value gain. Further if every method you mock is returning a preset value, there's no reason to verify expectations on it, because it's a stub that will allow verifying expectations on the output of the object/function under test.
As far as library naming, it's just a pet peeve stemming from "mock" somehow becoming synonymous with "test double". If people use a "mocking" library for stubs... well... that's good! :)
I have often - like on a team of 5-10 at least 2x per year - seen people wire a mock to a mock or a fake to a mock, and either not realize it (because it's under six layers of DI) or just they're not paying attention but someone said they "have to write tests" and trying to get it over with. And this is generally a lot less obvious, because the test suite is still full of assertions, sometimes even totally reasonable-looking ones. (Such tests are even sometimes "real tests" - but that the mock is doing what's expected, not of the desired SUT.)
There's also the general argument from the principle of least power. The less code in your doubles, the more certain you are the doubles are doing what you expect, and the more you're verifying what really matters in your code. Like how pure functions are preferable to impure functions when possible, having comprehensive tests without concerns about "side effects" also means your code has fewer relevant side effects.
The example outlined in the article isn't exactly a unit test: The change in state of one object changes the state of another object. If these are coupled that tightly I'd rather try to mock (stub) the dependencies of both objects and let them interact (test both at the same time), then verifying their final state.
Stubs just return preprogrammed data.
Mocks do the above, but can provide their own assertions about call order or number of times called.
State validation means checking a stub dependency of the SUT to make sure it’s in the right state. Behavior validation means you check a mock dependency to make sure the right functions were called the right number of times, and in the right order.
A stub is just a thing you can substitute for the dependency that knows how to tell the test it’s state, and a mock is a substitute for the dependency that knows how to tell it’s behavior, like which functions are called and how many times.
In terms of them being the same thing, they are both types of Test Doubles, so they both fall into a higher level category of “a substitute for a dependency of the system under test (SUT)”. The difference is how they’re used.
The theoretical distinction with Mocks is that they contain their own assertions. The practical distinction (when using mocking frameworks) is often that they allow testing a SUT that depends on concrete classes, without subclassing them.
We don't really care about those patterns of interaction as long as they end up doing the right thing: allowing the SUT to affect his "outside world" as intended.
Making assertions about the exact pattern of interaction (that is: using mocks) is too high granularity, and will make the tests break on valid refactorings. Because we don't care about the pattern itself—it's just an implementation detail—but about what it achieves.
That said, much of this still is valuable to think about and this article, to me, is not just word soup but I'll give you that it's not very focused. And I get confused since "mockist tdd" isn't really talked about explicility anymore. But I would argue the concept is very much alive as a natural part of behavior-driven development which encourages outside-in development with a focus on writing acceptance test first. So my question is if Fowlers worry from the past, that using mocks and asserting behaviour is focusing too much on the implementation. But like Fowler I haven't done BDD "for real" so I haven't seen how it plays out in the long term.
Suppose you have to test the irrigation system of a tree in your garden, you want to test how many times and how much water is used, you have two ways to do it:
1) State-based: run the system for a few hours, during which it should water the tree several times. At the end of that time, you check the state of the watered tree: Is the soil moist enough, is the tree well, are the leaves green, etc. (Obviously this is just an example as this test would be complex in real life, but it is to get the idea across).
2) Interaction: We place a flow meter, a device that registers how much water is flowing through the device and at what times. At the end of the day, check that the device has been called the correct number of times, with the correct amount of water each time, and we don't worry about checking the status of the tree.
Yeah, that'll happen with a lot of the testing "literature" from the 2005ish to 2015ish era.
It was a popular topic at the time, and one I was searching for answers on too. But I was working at a company that was ahead of the curve on testing and I got so frustrated at publicly available resources on testing. During that time and still to this day, when I read about testing online I kinda feel like I'm drunk. I have an idea of what's going on, things sorta make sense but not really. I'm only understanding bits and pieces. There are unnecessary and over-complicated details on some things, suspiciously light on meaty topics.
There was so much drivel written about testing back then that I still get angry remembering that people would say with a straight face "you don't need documentation, tests are your documentation."
I more understand the Martin Fowler article quite well, but only after struggling with it and revisiting it (sporadically) over several years, and I really think this by Mr, Khorikov gives a much clearer, more straightforward overview.
In the vast majority of the cases no one cares whether it returns a preset value or only counts the number of hits or whatever else it might do. And if that level of implementation detail becomes important, then it's described that way, not by the use of Fowler's terminology.
The shame of it is that the title of this essay makes it appear like it's simply an introduction to a lexicon, whereas the word definitions are actually a small part of the essay and there are more important topics presented (and presented fairly well).
Sure, but that's only the starting point here.
>The shame of it is that the title of this essay makes it appear like it's simply an introduction to a lexicon, whereas the word definitions are actually a small part of the essay and there are more important topics presented (and presented fairly well).
Yeah, but if you can't use the words to talk about these topics, it's going to be a lot harder to do so without getting verbose.
In essence classic xunit tests are not just unit tests, but also mini-integration tests. As a result many people like the fact that client tests may catch errors that the main tests for an object may have missed, particularly probing areas where classes interact. Mockist tests lose that quality. In addition you also run the risk that expectations on mockist tests can be incorrect, resulting in unit tests that run green but mask inherent errors.
https://blog.mockadillo.com/posts/the-importance-of-mocking-...