Skip to main content

The Difference Between a Mock and a Stub

Context of Modeling Assumptions
As you may recall, a unit test is sequence of instructions to run an automated test against an isolated unit of software code. A unit test may be considered to have these three phases:
  1. Modeling the assumptions
  2. Exercising the unit of code
  3. Verifying the acceptance criteria
Aside: This fits in nicely with the scrum agile framework, because a developer could theoretically develop one unit test for each user story. Each user story should already include concise details for assumptions and acceptance criteria.
It is particularly critical to model the assumptions before exercising the unit of code. The assumptions are the details of external factors that influence a unit's operation. It is important to call out the external assumptions to keep those distinct from the functionality of the unit itself. If a developer tries to write a unit test without modeling the assumptions, when they attempt to exercise the unit of code, they will also be exercising other code outside the unit. In that case, it is no longer a true unit test.

Importance of Calling Out Assumptions
For example: let's say we have the following user story: (I simplified this story for the purpose of this example leaving off elements which should be included in stories such as priority, points, and tasks)
  • Story: As a responsible parent, I want pictures of what is on my child's display, So that I can be aware of how they are using their device
    (See Snap Screen™ for a real Serafino Software™ product that is not the same but somewhat similar to this)
  • Assumptions:
    • Given the software is running on the child's device, When it requests a picture of what is on the display from the device environment, Then it will receive one
    • Given the software is running, When it requests to send a picture to the parent through the cloud provider, Then the picture will be sent to the cloud provider
  • Acceptance Criteria:
    • Given the software is running on the child's device, When it is 2:00 PM, Then it will request a picture of what is on the display from the runtime environment
    • Given the software is setup, When it receives a picture of the display, Then it will request the cloud provider to send the picture to the parent
Aside: Notice it can be helpful to write scrum user stories in the format:
As a [persona], I want [feature], So that [business value].

And it is helpful to write acceptance criteria in the format:
Given [precondition(s)], When [condition], Then [expected result].
Notice: The device environment that takes a picture of what is on the display, and the cloud provider that sends the picture to the parent, are external to the code in this actual unit. Therefore, that functionality should be called out as assumptions, and not excluded from being exercised by the isolated unit test. The code to implement those features should already be covered by its own testing. We could have an "end to end" test that included testing external functionality, but then it wouldn't be a unit test, it would be system test.

That is why we need to model the assumptions about the functionality of code external to the unit. The need to model these assumptions is the reason for the introduction of mocks or stubs.
We could have an "end to end" test that included testing external functionality, but then it wouldn't be a unit test, it would be system test.
Mocks and Stubs
Two main ways to model assumptions are called mocks and stubs. I have heard some developers make the mistake of using these terms interchangeably. I don't blame them, because in the past I have been unsure about the difference myself.

Stubs: Stubs could also be called fakes or dummies but as a former coworker once pointed out, such terminology is not necessarily the most excellent to inspire confidence in the uninitiated who overhear such terms. Therefore, I prefer the term, stubs. A stub is simply a piece of code that provides a model of an external assumption for a unit test. In other words, when a developer writes a piece of code to model an assumption for a unit test, he can consider that piece of code to be a stub.
A stub is simply a piece of code that provides a model of an external assumption for a unit test.
Returning to our example user story, we might write the following unit test (this is pseudo-code):
  • "Stub Device Environment":
    • When asked, return a "Stub Picture of the Display"
  • "Stub Cloud Service":
    • When asked, simulate sending a picture to the parent by recording the picture that has been requested to be sent
  • Use dependency injection to inject the stub device environment and stub cloud service into the unit
  • Exercise the unit
  • Verify that the stub cloud service has simulated sending the stub picture of the display by verifying it has recorded that the stub picture has been requested to be sent
Using stubs like this works fine for modeling a few big complicated external assumptions. And, sometimes it is still more feasible to use stubs in some cases. However, it takes much manual coding, and, especially when there are a lot of assumptions, it can be much more efficient to use mocks.

Mocks: Mocks are basically a way to automate the creation of stubs. Before the technology came along for mocking dependencies, it was hard work to manually create stubs to stub out all of the dependencies. Mocking frameworks provide mocks, which include the ability to record mock results to return for certain conditions, and the ability to verify that the mocks were exercised as expected. For example, we could improve our earlier test like this:
  • Create a "Mock Device Environment," which, when asked, returns a "Stub Picture of the Display"
  • Create a "Mock Cloud Service," (which can be asked to send a picture to the parent)
  • Use dependency injection to inject the mock device environment and mock cloud service into the unit
  • Exercise the unit
  • Verify that the mock cloud service has been requested to send the stub picture of the display to the parent
Notice that a picture of the display is simply data, so it does not make sense to try to replace the stub picture with a mock picture. For data such as pictures, we should still use stubs. For functionality, on the other hand, mocks improve coding efficiency and the elegance and quality of the resulting test code, because they automate the process of recording conditions, returning mock results, and verifying calls.
Mocking frameworks provide mocks, which include the ability to record mock results to return for certain conditions, and the ability to verify that the mocks were exercised as expected.
We can definitely see that mocks and stubs are not the same thing. They are quite different.

Comments

Popular posts from this blog

Reality Checks to Demystify Buzzwords

As an IT insider, I feel I have something valuable to offer nontechnical people in terms of correcting misinformation. Here are a few simple tests for some popular buzzwords in tech. When evaluating a product or service, if you can honestly answer Yes to the reality check question, the buzzword probably truly applies. If the answer is No, it is probably fake. agile Does it make the developers happy? blockchain Does it cut out the middleman? cloud Does it automatically scale? microservice Does it only do one thing? object oriented Is it mostly made of interfaces? RESTful When requests arrive at a certain address, are they ready to use (without parsing)? unit test Does it prevent the tested code from touching anything outside itself?

The Importance of Direction

Which would you say is more important: getting somewhere faster, pushing something harder, or going the right direction? It should be obvious that no matter how much speed or power you use, that won't do any good if you're going the wrong direction. It could also be pointed out that early in a journey, even a small change in direction makes a big difference in where you end up. Therefore, we should make sure we have our direction correct, as the first priority.

How (Not) to Handle Different Exceptions

Came across this sample from a certain multi-billion-dollar company, purporting to show how to implement exception handling. I slightly changed a few cosmetic details to make it anonymous. try { // ... } catch (GeneralException e) { if (e instanceof SpecificExceptionA){ // ... } else if (e instanceof SpecificExceptionB){ // ... } } This is a true actual story--you can't make this stuff up. Yeah, I thought it was pretty hilarious; so I felt like I had to share it.