What is the purpose of the Interfaces used in a Mock?

Asked

Viewed 406 times

3

I’m using a library called Moq which serves to create mocks that will be used in unit tests.

However, to create a mock it is necessary to specify an interface, as in the example of the Moq project page:

var mock = new Mock<ILoveThisFramework>();

or

var mock = new Mock<IQualquerInterface>();

More examples.

And this is exactly where my doubts arise.

Doubts

  1. What is the purpose of the Interfaces used in a Mock?
  2. What kind of relation the Interface has with the Mock?
  3. Why use an interface instead of a class that would represent an object?

2 answers

2


In fact, to create a mock, you don’t need an interface. You can create a mock of a class. What will define is how you designed your solution. When you use an interface and when you use a class you will enter another discussion, which can be seen in the link shared by @Maniero.

I will try to explain with examples.

Imagine you have this class:

public class CalcularIdade {

    public int calcular(int anoNascimento) {
        Data data = new Data();
        int anoAtual = data.getAno();
        return anoAtual - anoNascimento;
    }
}

Now imagine that for some reason you can’t use the class Data on the test. Taking this test will be difficult. One solution is to make that class Data injected into the class CalcularIdade. This way it will also be possible to inject the class mock Data. A first alternative would be this:

public class CalcularIdade {

    private Data data;

    public CalcularIdade(Data data) {
        this.data = data;
    }

    public int calcular(int anoNascimento) {
        int anoAtual = data.getAno();
        return anoAtual - anoNascimento;
    }
}

To Data is passed as parameter to the class CalcularIdade. Now I can pass the class mock Data for the class CalcularIdade. The actual application would look like this:

public static void main(String args[]) {
    CalcularIdade calcularIdade = new CalcularIdade(new Data());
    int idade = calcularIdade.calcular(1990);
    System.out.println(idade);
}

The test would look like this:

@Test
public void calcularTest() {
    Data dataStub = mock(Data.class);
    when(dataStub.getAno()).thenReturn(2018);

    int anoNascimento = 1990;

    CalcularIdade calcularIdade = new CalcularIdade(dataStub);
    int result = calcularIdade.calcular(anoNascimento);
    assertEquals(result, 28);
}

I made a mock of a class and it will work perfectly well. Note that this may not be the best solution, but the problem is in the design of the class and not in the test.

If in the future I wish to create another implementation for the class Data, this can be done by creating a class that inherits from Data. However, there will be a class dependency CalcularIdade with class Data. Depending on the solution, this dependency may not be a problem. But if it is necessary to remove the dependency, an interface will provide just that. It will refactor my class to that class CalcularIdade does not depend on implementation:

public class CalcularIdade {

    private IData iData;

    public CalcularIdade(IData data) {
        this.iData = data;
    }

    public int calcular(int anoNascimento) {
        int anoAtual = iData.getAno();
        return anoAtual - anoNascimento;
    }
}

My test:

@Test
public void calcularTest() {
    IData dataStub = mock(IData.class);
    when(dataStub.getAno()).thenReturn(2018);

    int anoNascimento = 1990;

    CalcularIdade calcularIdade = new CalcularIdade(dataStub);
    int result = calcularIdade.calcular(anoNascimento);
    assertEquals(result, 28);
}

If tomorrow I want a new implementation of Idata, my application is:

public static void main(String args[]) {
    CalcularIdade calcularIdade = new CalcularIdade(new NovaData());
    int idade = calcularIdade.calcular(1990);
    System.out.println(idade);
}

Could it be done with class? Yes. But there would be a coupling between Data and CalcularIdade, with the interface this coupling some.

Perhaps the library you are using does not allow you to create class mock. If this is the case, this may be a constraint to force the programmer to create a better design, but this is not a constraint of the mock conceptually speaking.

  • The library allows using class instead of interface. But now I understand the reason of the interface, is to increase the testability of the project and leave with a better designer.

0

Mock simulates the functionality/data of a class, so that the library can create this fake class, it uses the interface to implement the class with the parameters you pass, thus, the library can implement the methods with the necessary characteristics for the tests.

Browser other questions tagged

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