Testing with Doubles

MLSDev
6 min readFeb 14, 2018

--

Introduction

In this article we are not going to dwell on such general aspects as testing goals, what testing is, why it is necessary and whether it is necessary at all. These are fundamentals and if you got interested in this very article you should already know the basic things. In fact, it is a topic for a separate tutorial. If you don’t know the basics well enough, we recommend you to improve your knowledge first and then return to this material.

In this article we are going to dive into testing with doubles in unit tests. We would not recommend you to use doubles in integration tests because the latter run the entire scenario workflow without focusing on any details. It’s not that they don’t have to test these details, they just shouldn’t know anything about them at all. Integration tests should be maximally close to customer knowledge about system. The details of this implementation have to be checked on the level of unit tests.

Disclaimer

This article is mostly an author’s point of view and is not an official source. Don’t rely on it blindly but form your own opinion and analyze. If the content of the article looks highly consistent to you and if it is very close to your vision, we recommend you to have a look at the attached links. If you would like to dispute something, feel free to contact the author at shvetsov1988@gmail.com

Testing classifications

Jay Fields distinguished two kinds of tests in his works.

A green lozenge in the picture is a unit test in both cases, where the arrow points to the main object for testing (outlined by a green dotted line). Hereafter we will call an object for testing SUT(System Under Test/ Subject Under Test). The SUT also contains information about the connection with collaborators that act as elements in the chain of the overall process.

The whole difference between sociable and solitary tests is that in sociable tests we allow these elements to make real calls. In solitary tests, we substitute these collaborators for doubles.

Doubles. Types of doubles.

As we have already stated, doubles are a common notion for all kinds of fake objects from the perspective of testing. There are a lot of types of doubles but we will speak only about two of them usually applied in our practice. These are stubs and mocks. What is the difference between them?

Let’s look at the screenshot first and try to find mocks and stubs.

This service (UserCreator) saves a user in the system and transfers data via Pub/Sub. Look at #1, 2, 3, 4. What is a mock and what is a stub?

In fact, there are no mocks here. If you assume that it could be option 1 and 2, they aren’t mocks from the ideological point of view. They are closer to Test spies and #3 and #4 are already stubs.

What are mocks and stubs and what is the difference between them?

The difference between them is more than just at the level of syntax, they are ideologically different.

There exist two ideologies in testing with doubles.

The first one calls for result verification through state verification. In the example above we block out the AR call (with the help of the allow method) and instead of calling a method we return a state at once which is verified at the end of the test. These are stubs. Put in other words, if there is no method call stubbed before it doesn’t mean that the test goes wrong. We are interested only in verifying returned object. It doesn’t matter from the test point of view how this object was received, via real method call or stubbed method.

Mocks, in their turn, are a part of the ideology of behavior verification. We check whether the method has been called and whether it has been possibly called with definite parameters. That is where the fact of calling a certain method is important for us. No call means that the test has been failed. Actually we don’t need the data this method returns for further processing because it does not confirm the test pass. A mock stops being a mock when it returns anything.

The RSpec syntax helps to separate these two ideologies with the allow and expect methods.

Allow can cut off a method call to return any state and it is not a verifier because a test should be verified by a result, not behavior. Using the allow hooks you choose state verification for the test by default. The expect hooks verify a method call in particular and return an error if there is no call. It is behavior that you test in this case. If expect returns a state it is a reason to think whether you should check if the data for verification returns exactly with this method (seems like you shouldn’t).

You can easily derive a formula from this when to use stubs and mocks.

If you want to use a double on one of your collaborators and the result of collaborator performance should return any state for further verification you need a stub.

If the result of collaborator performance is not important in SUT, you can use a mock. Of course, this collaborator should be covered by a separate unit test if it’s your implementation. If this is a class object of a third-party library, you can give complete control over the test of this method to an integration test.

Reasons for disliking testing with doubles

Duplicating implementation

To make a double work we have to put a hook in a specific scenario in advance.

Leading to brittle tests

We decided to change the user search logic and replaced find_by with find. Now our database won’t return anything and the stub will not return too because another method is called. In database testing we wouldn’t need to change anything but here we have to copy the logic again.

Nested doubles

If for some reason we decide to change the implementation again and the work with a double presupposes an additional call of some methods and parameter transfer, we will need to build nested doubles and copy the implementation again which is not good and clear.

Not to face the above mentioned issues or to face them consciously you should follow some rules. They appeared from the same source as TDD (test-driven development) which is Java.

Learn about the rules for using doubles in the full article on MLSDev blog.

--

--

MLSDev
MLSDev

Written by MLSDev

#IT #outsourcing. #Mobile and #Web Apps #Development. #iOS. #Android

No responses yet