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

3

I'm using a library called Moq that is used 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 it is exactly at this point that my doubts appear.

Questions

  • What is the purpose of the interfaces used in a Mock?
  • What kind of relationship does the Interface have with Mock?
  • Why use an interface instead of a class that would represent an object?
  • asked by anonymous 02.07.2018 / 01:10

    2 answers

    1

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

    I'll 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 not use the Data class in the test. Doing this test will be difficult. One solution is to have the Data class injected into the CalcularIdade class. In this way you can also inject the mock of class 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;
        }
    }
    

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

    If in the future I want to create another implementation for the class Data , this can be done, just create a class that inherits from Data . However, there will be a dependency of class CalcularIdade with class Data . Depending on the solution, this dependence may not be a problem. But if it is necessary to remove the dependency, an interface will provide just that. Ireir refactor my class so that the CalcularIdade class is not implementation dependent:

    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 stays:

    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.

    Maybe the library you are using will not allow you to create class mock. If this is the case, this may be a constraint for forcing the programmer to create a better design, but this is not a mock constraint conceptually speaking.

        
    08.07.2018 / 19:25
    0
    Mock simulates the functionality / data of a class, so the library can create this fake class, it uses the interface to implement the class with the parameters you pass, so the library can implement the methods with the features needed for testing.

        
    02.07.2018 / 21:41