Create a mock for any instance of a class

Asked

Viewed 1,483 times

2

How do I mock any instance of a class? I would like to do this so I don’t have to mock an object and have to put it inside a class. Example:

[TestFixture]
public class TokenTest
{

    GeradorDeToken target;

    [Test]
    public void GeraTokenComSucesso()
    {
        int[] array = { 19, 28, 37, 46, 55 };

        var mockGeradorDeArray = new Mock<GeradorDeArrayParaToken>();

        mockGeradorDeArray.SetupAny(g => g.GeraArray()).Returns(array);

        string tokenEsperado = "1E7C6XB9F8A";

        token = new GeradorDeToken();

        Assert.That(target.GeraToken(), Is.EqualTo(tokenEsperado));
    }


}

public class GeradorDeToken
{
    private int[] arrayNumeros;

    public GeradorDeToken()
    {
        this.arrayNumeros = new GeradorDeArrayParaToken().GeraArray();
    }

    public string GeraToken()
    {
        //Criação do token baseado no arrayNumeros
        return "";
    } 

}

public class GeradorDeArrayParaToken
{

    public virtual int[] GeraArray()
    {
        int[] array = new int[5];

        //Gero numeros randomicos

        return array;
    }
}

I illustrated creating the fictitious method Setupany (does not exist in the Moq library). What is the correct way that this framework solves this question?

1 answer

3

That is not possible.

To test the class GeradorDeToken using unit tests, we have to isolate it from its dependencies - and this is done through dependency Injection. This injection can be made through the constructor, properties (unusual and unadvisable), or parameters of a method. In this case, it seems you need constructor Injection.

public class GeradorDeToken
{
    private int[] arrayNumeros;

    public GeradorDeToken(IGeradorDeArrayParaToken gerador)
    {
        this.arrayNumeros = gerador.GeraArray();
    }

    public string GeraToken() {}    
}

public interface IGeradorDeArrayParaToken {}
public class GeradorDeArrayParaToken : IGeradorDeArrayParaToken {}

If your goal is to avoid repeating the injection of dependencies in the test, you can use Autofixture + Automoq, an essential tool for unit testing.

var fixture = new Fixture().Customize(new AutoConfiguredMoqCustomization()));

// Sempre que uma dependência ou um mock precisar de um objecto to tipo `int[]`, a variável `array` será usada.
fixture.Inject(array);

var gerador = fixture.Create<GeradorDeToken>(); // As dependencias serao automaticamente injectadas.

Thanks to AutoConfiguredMoqCustomization, Interfaces or abstract classes mocks will be automatically created, and your methods/properties will be setup. There are also plugins for xUnit and Nunit to facilitate the creation and customization of fixture.

Two notes about your implementation:

  • Uses an interface instead of a class with a virtual method.
  • The method GeraArray should be called within the method GeraToken and not in the constructor. Otherwise, successive calls to the method GeraToken will always return the same result - I do not believe that is the expected behavior.

Browser other questions tagged

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