What are the differences between mocks and fakes?

Asked

Viewed 247 times

10

When we implement tests in software, Mocks and Fakes are two techniques or approaches to isolate the code being tested from the rest of the system.

Without going into it:

  • Mocks are like empty shells with predefined behaviors, such as: when calling method X, return value Y
  • Fakes are fully or partially functional objects implemented especially for tests that aim to simulate the functioning of the system, but in a relatively isolated way.

But what would be the relevant differences between the two concepts for the correct implementation of tests? Some relevant aspects:

  • What types of tests (unit, functional, integration) work best with both?
  • Are there specific situations where it is more evident that it is worth using one or the other? Examples in any language are welcome.
  • Which of them or in what sense they are better or worse when there are system changes, that is, to maintain the tests?

Update: I don’t want the definition of concepts, this is already in the question. What I want are differences in the application, as described in the above topics, but not limited to them. Someone who’s used both must have an idea of what I’m talking about.

  • The original question did not mention this, but I have already answered what it is, the details are not yet: http://answall.com/a/36756/101

  • I think I can pass, but I found it curious how people are closing something and nobody dared to take a vote to close this and even others. Is playing with people’s limits :) People vote around even :)

  • 1

    @bigown Confess that I did it on purpose. : D But according to my update, I’m not asking about the definitions of concepts but the details of how to apply.

  • @utluiz here has a practical question on the subject. I believe she has a strong relationship with your question and can help to better understand the doubts between mocks and fakes.

1 answer

2

What types of tests (unit, functional, integration) work best with both?

Are there specific situations where it is more evident that it is worth using one or the other? Examples in any language are welcome.

To unit tests, mocks are the main choices and I also believe that fakes have their place. Commonly, in unit tests we are testing the behavior of a specific class and trying to ignore to the maximum the dependencies of this class.

In this act of "ignoring" their dependencies, we use the concept of mock to just make these dependencies behave in a certain way for each test.

With Mock

Let’s go to an example in Java, using the Mockite. Let’s say I want to test a service CreditoService that depends on a ParametroService and that consults a value called bonus through this parameter class. In this case we are concerned to test the implementation of CreditoService and we don’t care how Parametroservice works:

ParametroService parametroService = mock(ParametroService.class);
when(parametroService.getBonus(any(Empresa.class))).thenReturn("10.00");
CreditoService creditoService = new CreditoService(parametroService);

In the example above, I simply said to the parametroService return "10.00" to me bonus independent of empresa the class receives as a parameter.

And the main difference that separates the Mock from a Fake is that with Mocks you can check and confirm if certain actions occurred with that Mock, because all these actions on top of the mock are recorded. In the previous example I created a mock and, although I defined an action expected by it, I did not check if it was actually called. Thus, I can also add a check that the bonus method of parametroService was called a certain number of times:

verify(parametroService, times(1)).getBonus(any(Empresa.class));

With Fake

In this same example, I could use a Fake of ParametroService. Let’s just say, depending on how much empresa, I would like the ParametroService do something different internally; any kind of logic on top of the company. For example, if the past company were a subsidiary, it would not have a bonus. We might have something like this then:

ParametroService parametroService = new ParametroServiceFake();
CreditoService creditoService = new CreditoService(parametroService);

Being ParametroServiceFake an implementation of the same interface ParametroService used by the actual implementation:

class ParametroServiceFake implements ParametroService {
    String getBonus(Empresa empresa) {
         if (empresa.isFilial()) {
             return "0";
         }
         return "10.00";
    }
}

In integration and functional tests this concept still exists, however the Fakes usually rule.

For example, in an integration test I can create a database in memory when making a Fake of a repository class (Repository), in which data to be entered into a supposed database is stored in a Map Fake internal, which can even provide search methods for this data "saved" in the repository.

I can do the same by making a Fake of a class used to simulate the behavior of a WebService:

 class WebServiceFake implements WebService {
    String consultarNomeCliente(String cpf) {
         if (cpf.equals("123.123.123-11"))
              return "Augusto Moraes Filho";
         return "";
    }
}

As you can see, it’s a functional implementation but far from the real one. But when you need to simulate certain behaviors of external systems, this technique comes in handy.

We can also use it in integration tests or functional mocks. At Spring this possibility exists and is well accessible through the @MockBean, in which you can, in any integration/functional test, make a mock of any injectable class.

Which of them or in what sense they are better or worse when there are system changes, that is, to maintain the tests?

In general, mocks give less maintenance, mainly because of the context they are inserted: local, unit and isolated tests of the other tests.

Already the Fakes require functional code implementation. If we have code implemented, we have maintenance. And the problem only pióra when one Fake needs to be "aligned" with other’s data Fake.

Let’s take an example. Let’s say I want to do an integration test that uses data from two different external systems. One of them has the data of person and the other of the current account. We have then the person "Eduardo", of CPF "123.123.123-11" and with the current account "9876-0". So I can have one Fake for each system. So far, so good.

Let’s get to the problem now. If I get Eduardo’s number on the first system, he needs to come. As if I do a search for the number in the second system, to have your current account. If, by any chance, one of the two sides doesn’t bring results by searching for the number, my test will fail. This alone will make me need to worry that both Fakes have CPF with person data and current account and that no one, in the future, "break" this link between both that exists in the actual usage scenario.

  • The definition I have read about "mocks" is in complete disarray of your answer. However, I do not know who is right, nor whether there are situations where the context makes one right and the other wrong.

  • @Jeffersonquesado, share your mock definition. Perhaps my explanation was not clear, so (and there is request of the author of the topic) brought examples in the reply.

  • One of my reading songs: https://martinfowler.com/articles/mocksArentStubs.html he may not be sure, but he is Martin Fowler xD

  • Hehehe, I’m going to improve on the mock part, I think the crucial difference is that with Mocks you can check if what you expected really happened. Other than that, I’m trying to define Mock according to its functioning and function in the frameworks dedicated to it (Easymock, Mockito, etc).

Browser other questions tagged

You are not signed in. Login or sign up in order to post.