Escrever testes é uma boa prática que dispensa comentários, certo?

Eu tenho certeza que todos escrevem testes em seus projetos, não é mesmo?

Eu tenho visto muitos projetos com uma boa cobertura de testes, mas não é incomum eu ver que estão escritos testando a classe concreta. O projeto até possui intefaces, mas ainda assim no projeto de testes temos os famosos new Objeto() para chamar as funcionalidades no teste de integração.

Uma vez eu perguntei a um colega: Porque você não chama a interface para fazer os testes? E ele me respondeu: Porque não dá!

Esta resposta me causou uma certa surpresa. Busquei outros projetos e vi que vários deles testavam as classes concretas mesmo tendo interface.

Outros projetos até testavam usando a interface, mas usavam umas “soluções” (gambiarras na verdade) bem complexas e desnecessárias.

A grande questão foi como fazer a Injeção de Dependência no projeto de testes uma vez que, no .Net Core, elas ficam no Startup.cs do projeto Web principal?

Aqui vou tentar explicar de uma forma bem simples como escrever testes usando as interfaces do projeto e acessando seus métodos com Injeção de Dependência.

A primeira coisa que devemos fazer é instalar o
Microsoft.Extensions.DependencyInjection no projeto de testes. Usaremos este pacote para fazer a Injeção de Dependência.

Install-Package Microsoft.Extensions.DependencyInjection

No projeto Web, criei uma Model Calculator.cs com métodos bem simples que vão servir de exemplo.

    public class Calculator : ICalculator
    {
        public int Sum(int a, int b)
        {
            return a + b;
        }

        public int Subtract(int a, int b)
        {
            return a - b;
        }

        public int Multiply(int a, int b)
        {
            return a * b;
        }
    }

    public interface ICalculator
    {
        int Sum(int a, int b);
        int Subtract(int a, int b);
        int Multiply(int a, int b);
    }

Como podem ver, é tudo bem simples, o foco aqui é vermos como ficará nosso projeto de testes.

Depois do package instalado, vamos escrever nosso teste utilizando a interface e não a classe concreta. Vamos fazer a Injeção de Dependência no construtor da classe de teste.

    public class CalculatorTest
    {
        private readonly ICalculator _calculator;

        public CalculatorTest()
        {
            var service = new ServiceCollection();
            service.AddTransient<ICalculator, Calculator>();

            var provider = service.BuildServiceProvider();
            _calculator = provider.GetService<ICalculator>();
        }

        [Fact]
        public void Test_Sum()
        {
            var result = _calculator.Sum(2, 3);
            Assert.Equal(5, result);
        }

        [Fact]
        public void Test_Subtract()
        {
            var result = _calculator.Subtract(2, 3);
            Assert.Equal(-1, result);
        }

        [Fact]
        public void Test_Multiply()
        {
            var result = _calculator.Multiply(3, 2);
            Assert.Equal(6, result);
        }
    }

Reparem no construtor da classe CalculatorTest. Utilizamos o ServiceColleticon() para fazer a Injeção de Dependência “manualmente”. Em seguida criamos o ServiceProvider e atribuímos os métodos da classe concreta usando o GetService<ICalculator>().

Pronto! De uma forma bem simples é possível usar as interfaces do nosso projeto para escrever nossos testes.

O código usado está disponível no meu GitHub.