c# – What is the purpose of the Interfaces used in a Mock?

Question:

I'm using a library called Moq that 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 on the Moq project page:

var mock = new Mock<ILoveThisFramework>();

Where

var mock = new Mock<IQualquerInterface>();

More examples .

And it is exactly at this point that my doubts appear.

Doubts

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

Answer:

In fact, to create a mock, you don't need an interface. You can mock a class. What will define is how you designed your solution. When to use an interface and when to use a class 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 Data class in the test. Taking this test will be difficult. One solution is to have the Data class be injected into the CalcularIdade class. This way it will also be possible to inject the mock of the Data class. 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;
    }
}

The Data is passed as a parameter to the CalcularIdade class. Now I can pass the mock from the Data class to the CalcularIdade class. 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 up of a class and it will work perfectly fine. Note that this may not be the best solution, but the problem lies in the design of the class, not the test.

If in the future I want to create another implementation for the Data class, that can be done, just create a class that inherits from Data . However, there will be a dependency of the CalcularIdade class with the Data class. Depending on the solution, this dependency may not be an issue. But if it becomes necessary to remove the dependency, an interface will provide just that. Ireir refactor my class so that the 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 IData implementation, 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 disappears.

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

Scroll to Top