Injetando construtor em código legado com Autofixture

  • Rafael Miceli
  • 18 Mai 2017

Quando trabalhando com projetos legados¹ e estamos refatorando algumas classes para cobrir com testes uma das coisas mais comuns de se encontrar são acoplamentos\dependências² com outras classes que fazem comunicação com Banco de Dados ou com algum serviço externo.

1 Projetos legados de acordo com a definição do Michael C. Feathers é de projeto que não está coberto com testes que ele cita em seu livro Working Effectively With Legacy Code. Já David Bernstein coloca em seu livro que Projeto Legado é aquele que você não tem confiança em realizar mudanças no mesmo

2 Acoplamentos ou dependência em software é geralmente quando criamos uma ligação entre classes aonde um depende da implementação da outra (não tendo uma interface no meio para dependermos da abstração). Lembrando que nem toda dependência é ruim, dependência entre classes do Domain são muito comuns

Muitas das vezes vamos ver classes com as dependências de uma dessas 3 formas:

Com a dependência sendo feita logo antes da chamada:

public class MateriaEscolar
{

    public void AdicionarMateria(Materia materia)
    {
        //Regra de negócio

        //Dependencia
        MatriaEscolarRepository_Dao dao = new MatriaEscolarRepository_Dao();
        dao.Adicionar(materia);
    }
}

Com a dependência sendo feita no membro da classe:

public class MateriaEscolar
{
    //Dependencia
    private MatriaEscolarRepository_Dao _dao = new MatriaEscolarRepository_Dao();

    public void AdicionarMateria(Materia materia)
    {
        //Regra de negócio

        _dao.Adicionar(materia);
    }
}

E em alguns casos melhores com a dependência no contrutor:

public class MateriaEscolar
{
    private readonly MatriaEscolarRepository_Dao _dao;

    public MateriaEscolar()
    {
        //Dependencia
        _dao = new MatriaEscolarRepository_Dao();
    }

    public void AdicionarMateria(Materia materia)
    {
        //Regra de negócio

        _dao.Adicionar(materia);
    }
}

E nos dois últimos casos (o primeiro você vai precisar entender melhor o ciclo de vida da classe) para tornarmos nossa classe “testável” Repository\Dao nós extraímos uma Interface da Repository\Dao, trocamos nosso Field que era a classe pela Interface que acabamos de criar e criamos um novo Construtor injetando nosso Repository\Dao, ficando da seguinte maneira:

public class MateriaEscolar
{
    private readonly IMatriaEscolarRepository_Dao _dao;

    public MateriaEscolar()
    {
        //Dependencia
        _dao = new MatriaEscolarRepository_Dao();
    }

    public MateriaEscolar(IMatriaEscolarRepository_Dao dao)
    {
        _dao = dao;
    }

    public void AdicionarMateria(Materia materia)
    {
        //Regra de negócio
        
        _dao.Adicionar(materia);
    }
}

Com isso não quebramos as classes que dependem da classe MateriaEscolar e temos um construtor aonde podemos Injetar nossos Mocks para realizar nossos testes.

Injetando dependência com AutoFixture

Já falei do Autofixture aqui e ele é uma excelente ferramenta junto com seu AutoMoq Customization para injetar as dependências automaticamente. Porém quando temos um construtor vazio e o um construtor com as dependências para injetarmos como no caso mostrado acima, ao criarmos nosso System\Subject Under Test da classe MateriaEscolar da seguinte maneira:

var sut = fixture.Create<MateriaEscolar>();

Por default o AutoFixture vai inicializar com o construtor sem parâmetros. Como podemos então chamar sempre o construtor com parâmetros que queremos injetar?

Para isso antes de criar nosso sut, adicionamos a seguinte customização:

fixture.Customize<MateriaEscolar>(c => c.FromFactory(new MethodInvoker(new GreedyConstructorQuery())));

Com isso nosso sut vai ser construído usando o construtor com as dependências que queremos injetar, e se estivermos usando AutoMoq elas vão ser injetadas dinamicamente.

comentarios com Disqus Disqus