DEV Community

Inácio Bueno
Inácio Bueno

Posted on

Quem vigia os vigilantes: uma introdução a testes de mutação

Testes de mutação podem dar ótimos indicadores de como / se os seus testes estão realmente preservando o estado de comportamento original da sua regra de negócio. Neste breve texto irei introduzir conceitualmente o que são testes de mutação e apresentar uma ferramenta para fazer esse tipo de análise.
A ideia é bem simples: mutações são alterações no seu código, e se essas alterações no seu código não reprovarem no seu teste, pode ser que o seu teste seja ruim ou incompleto. Um exemplo rápido, imagine uma função que verifica se alguém é maior de 18 anos:

    public class Verificador
    {
        public bool EhMaiorDeIdade(int idade)
        {
            return idade >= 18;
        }
    }
Enter fullscreen mode Exit fullscreen mode

E que para o teste dessa função você tenha um único teste:

        [Fact]
        public void Deve_Retornar_Verdadeiro_Para_Uma_Idade_Maior_Ou_Igual_18()
        {
            var verificador = new Verificador();

            var resultado = verificador.EhMaiorDeIdade(19);

            Assert.True(resultado);
        }
Enter fullscreen mode Exit fullscreen mode

No primeiro olhar, tudo parece ok, a função é para verificar se é maior de idade, 19 anos seria alguém maior de idade o teste passou, então está tudo certo, certo?! É claro que esse é um exemplo simples e fácil de verificar que não, mas uma modificação (mutação) de "return idade >= 18;" para "return idade > 18;" continuaria fazendo com que o seu teste fosse aprovado, porém essa modificação quebrou a sua regra de negócio mas seu teste - que deveria ser aquilo que te alerta que alterações recentes alteraram crucialmente o comportamento inicialmente definido pela sua regra de negócio - não te diz nada.
Aqui entra o Stryker, uma ferramenta que irá fazer essas mutações no seu código, e para cada mutação que for possível fazer, ela irá executar o teste. Se o seu teste passar com uma mutação (alteração), seu teste está incompleto; Se as mutações fizerem o seu teste reprovar elas, você está no caminho correto; digo "no caminho correto" porque as mutações feitas pela ferramenta tem sua limitações e que mutações/alterações feitas ao decorrer do tempo por programadores reais, têm bem mais sutilezas.
Eu criei aqui dois projetos bem simples, um projeto console e outro é um projeto de testes. Caso queira fazer o mesmo:

dotnet new console -n console.mutation; dotnet new sln -n solucao; dotnet new xunit -n teste.mutation
Enter fullscreen mode Exit fullscreen mode

A ferramenta você pode instalar com:

dotnet tool install -g dotnet-stryker
Enter fullscreen mode Exit fullscreen mode

Entre no diretório do projeto de teste e rode:

dotnet-stryker
Enter fullscreen mode Exit fullscreen mode

No caso do nosso exemplo, teríamos o seguinte resultado pelo terminal:

100.00% │ Testing mutant 2 / 2 │ K 1 │ S 1 │ T 0 │ ~0m 00s │                                                       00:00:02                                                                                                                           
Killed:   1
Survived: 1
Timeout:  0
Enter fullscreen mode Exit fullscreen mode

Mas também tem uma página html disponibilizada para ver com mais detalhes:

Image description

O diff em verde no código é a mutação feita pela ferramenta, e como indica no filtro ela foi a mutação que sobreviveu. Como Podemos matar ela? Simples, testando melhor: Se a função verifica se um número é maior ou igual 18, é fácil de ver que nosso teste testa apenas se maior e não se é maior ou igual. Ao teste vamos adicionar:

[Fact]
        public void Deve_Retornar_Verdadeiro_Para_Uma_Idade_Igual_18()
        {
            var verificador = new Verificador();

            var resultado = verificador.EhMaiorDeIdade(18);

            Assert.True(resultado);
        }
Enter fullscreen mode Exit fullscreen mode

O teste completo fica assim:

    public class TesteVerificador
    {
        [Fact]
        public void Deve_Retornar_Verdadeiro_Para_Uma_Idade_Maior_Ou_Igual_18()
        {
            var verificador = new Verificador();

            var resultado = verificador.EhMaiorDeIdade(19);

            Assert.True(resultado);
        }

        [Fact]
        public void Deve_Retornar_Verdadeiro_Para_Uma_Idade_Igual_18()
        {
            var verificador = new Verificador();

            var resultado = verificador.EhMaiorDeIdade(18);

            Assert.True(resultado);
        }
    }
Enter fullscreen mode Exit fullscreen mode

E rodando novamente a ferramenta temos:

100.00% │ Testing mutant 2 / 2 │ K 2 │ S 0 │ T 0 │ ~0m 00s │                                                       00:00:02                                                                                                                           
Killed:   2
Survived: 0
Timeout:  0
Enter fullscreen mode Exit fullscreen mode

E na parte gráfica:

Image description

Conseguimos matar a mutação e assim produzindo um teste mais significante.
Espero que tenha gostado do texto e que tenha aprendido algo novo. Qualquer dúvida, leia a documentação. Até o próximo texto.

Top comments (0)