Category: Blog, Android, iOS, Development

6 Misconceptions About TDD – Part 5. Mocks, Mocks Everywhere!

Another part of our guide to the TDD cycle – this time, we take a closer look at mocks in testing.

TDD cycle

Welcome to the next part of our guide to the TDD cycle! Let’s dive in.

An essential part of the TDD cycle methodology is writing tests. Many of our features depend of other (external) services that we couldn’t use in our test. Examples of these services are: sending emails, oauth2 authentication or gathering actual exchange rates.

Why can’t we use them? Because investigating the results is hard and/or we must pay for using them. Or because using a real implementation would increase the time of execution dramatically.

In such cases, if we want to be able to test these features we need to declare a contract (e.g. as interface) between these functionalities. That’s how we can inject a specific implementation for testing purposes.

Introducing mocks in the TDD cycle

When talking about testing abuse, many developers use the word “mock” meaning an implementation which is substitute for the real implementation for testing purposes.

According to the terminology used by Gerard Meszaros in XUnit Test Patterns, a mock is one of the few options for handling the injection of a specific implementation for testing purposes. Meszarosa uses term “doubler” as a general term describing this mechanism. This is an analogy to the world of movies where the doubler of an actor plays scenes which require some special skills or are dangerous.

Aside from mocks, there are also dummies, fakes, stubs and spices (based on the XUnit Test Pattern, there are also some alternatives names).

Here’s a short overview of these doublers.

Dummy

Representing doublers that we only need for a fulfilled signature of the function/methods in test time. They’re useful when creating of required object is too complicated.  The interaction between the dummy and the rest of the testing code is none or negligible.

Fake

This is a real but simplified implementation of the dependency functionality we need for testing. It’s used when the double feature is hard to the modeled process with stub (or when it’s impossible) or when the real implementation is too slow for testing. Yeah, obviously an example is using a database in the memory as a substitute for (NO)Sql database.

Spy

Spy is an extended version of stub, which stores information about how they are executed (for example, which parameters are used). We need them when we want to test the indirect state of a functionality which isn’t available outside the functionality that we’re going to test.

Mock

These doublers are used to describe the expected interaction between the system under test and them provide a mechanism to verify if this interaction occurred. It’s the only one that represents the behavior testing of feature.

For more details about doublers, please check XUnit Test Patterns by Gerard Meszaros.

TDD cycle mocks

Classical vs. mockist TDD

When using the first four types of doublers, we focus on testing the state of system under test. On the other hand, testing using mocks concentrates on the behaviors and interactions between features.

Both ways (classical and mockist) have their advantages and disadvantages. When we use the mockist way, we need to initialize only the direct collaborators of the system we want to test.

Advantages of classical testing

In the classical way, we need to initialize also the collaborators of collaborators, and so forth. A bug in one place will not propagate to other tests. When focusing on the testing state, we are using the real implementation whenever we can. However, finding the source of the bug is much more time-consuming.

The greatest advantage of using classical way of testing is the fact that our unit tests are also mini integration tests. As I mentioned before, we are using the real implementation. The second important thing is the fact that classical testing is low coupling to the real implementation then mockist. We are focusing on the expected state which is less susceptible to changes then the changes in interfaces which is strongly coupled to mockist tests.

Based on those advantages and disadvantages we are more likely to use classical/state testing in our daily work. But the decision of which path to choose should go to the developer or the development team.

In many cases, it’s natural or more obvious which type of test needs to be used to test features easily. For example, to test a features like login or sending an email I would use a mock (I expect that some action occurs). But for calculating a discount for an order, I’d prefer the classic way (because I expect to get some values).


The agenda of the article series about the TDD cycle “6 Misconceptions about TDD” is the following:

  1. TDD brings little business value and isn’t worth it
  2. We all understand the key laws of TDD in the same way
  3. TDD cycle can be neglected
  4. There is one right granularity of steps in TDD
  5. Mocks, mocks everywhere!
  6. Tests loosely coupled with code are reliable

About the author

Bartosz Skuza

Bartosz Skuza

Web & React Native Developer

Full Stack Developer with 10 years of experience. He specializes in web technologies, and has a natural predilection for React. Bartosz loves being up to date with new solutions in IT. He is an enthusiast of Test-Driven Development and writing clean code. A superfan of long walks with his dogs; board & tabletop games freak.