Como testar os meus testes?
Depois de um longo período sem publicar conteúdo, volto com um tema bem interessante!
O título parece errado mas é isso mesmo o que você leu! Seu teste unitário provavelmente está ruim e eu vou tentar provar nas linhas abaixo.
Não vou entrar em detalhes sobre o que é um teste unitário, pirâmide de testes etc porque se você chegou até aqui é porque provavelmente você já escreve teste unitários. Um único ponto que vale a pena abordar é a cobertura de testes de um projeto.
Uma coisa é fato: Escrevemos testes unitários para garantir a qualidade da nossa aplicação, facilitar manutenções futuras (o famoso refactoring), melhorar a escrita de código (TDD) entre muitos outros benefícios.
Geralmente definimos um índice de cobertura de testes mínimo para garantir a qualidade do projeto. Exemplo: 70% de cobertura de testes unitários. Abaixo disso a build quebra (se houver um processo de build e deploy automatizado).
Essa métrica pode ajudar, porém, não garante que os testes unitários foram bem escritos, afinal, a cobertura de testes valida somente se determinada linha de código passou por um teste unitário.
Vou usar um exemplo simples, mas MUITO simples para validar os conceitos que estamos discutindo. O código abaixo concatena duas strings informadas por parâmetro e o seu teste unitário.
public class OperacoesString
{
public string Concatenar(string t0, string t1)
{
return $"{t0} {t1}";
}
}
[Fact]
public void Concatenar_ConcatenarDuasStrings()
{
//Arrange
string t0 = "Testes com";
string t1 = "Stryker";
//Act
var resultado = new OperacoesString().Concatenar(t0, t1);
//Assert
Assert.NotNull(resultado);
}
Se executarmos uma ferramenta para avaliar o índice de cobertura de testes (ex: Sonarqube) vamos obter um índice de 100% de cobertura de testes.
Ok! Meu código está com 100% de cobertura de testes, mas e os meus testes, eles estão realmente bons? Nas próximas linhas mostro como você pode verificar a qualidade do seu teste unitário através dos testes de mutação.
E o que seria um teste de mutação?
Como dito anteriormente, nós geralmente utilizamos a cobertura de linhas de código para medir a qualidade dos testes unitários.
Essa métrica não verifica a qualidade das asserções e uma solução para este problema é utilizar uma ferramenta que altere sua implementação fazendo com o que seu teste falhe.
Em resumo: os testes de mutação permitem que você verifique a qualidade dos testes unitários inserindo bugs temporariamente em seus testes.
Escrever teste já dá um certo trabalho e testar os testes deve ser mais trabalhoso ainda, certo? Eu já entendi que há como verificar a qualidade dos meus testes mas quem pode fazer isso por nós?
Apresento-lhes o Stryker
O Stryker é uma ferramenta de teste de mutação que verifica a qualidade das asserções de testes de unidade. Ele está disponível para C#, JS e Scala.
https://stryker-mutator.io/stryker-net/quickstart
O primeiro passo para utilizar a ferramenta é efetuar a instalação. Neste exemplo vamos fazer uma instalação global utilizando o comando
dotnet tool install –g dotnet-stryker
Também é possível instalar a nível de projeto, o procedimento está disponível em https://stryker-mutator.io/docs/stryker-net/Getting-started
Após a instalação basta navegar via powershell, bash etc até a pasta do projeto de testes e executar o comando de execução do stryker especificando qual projeto deve sofrer mutação caso haja mais de uma camada testada no projeto.
dotnet stryker –project-file=‘C:\<caminho_projeto>\src\TesteMutacao\TesteMutacao.csproj’ –reporters “[‘progress’, ‘html’]”
Os testes forem executados somente em uma única camada não é necessário especificar o projeto basta executar o comando dotnet stryker –reporters “[‘progress’, ‘html’]”
O resultado da execução gera um relatório html onde você visualiza os resultados das mutações. Se um teste sobreviveu é porque o teste não quebrou, afinal o objetivo do teste de mutação é quebrar os seus testes.
Como podemos ver na imagem acima o teste sobreviveu a mutação. Isso significa que algo não está bom em nosso teste. Lembra do índice de cobertura que comentamos acima? Se não efetuarmos os testes com o Stryker nosso projeto estaria com 100% de cobertura de código e mesmo assim não estaria isento de bugs. Então vamos refatorar nosso teste.
[Fact]
public void Concatenar_ConcatenarDuasStrings()
{
//Arrange
string t0 = "Testes com";
string t1 = "Stryker";
string expected = "Testes com Stryker";
//Act
var resultado = new OperacoesString().Concatenar(t0, t1);
//Assert
Assert.Equal(expected, resultado);
}
E voilá! Após refatorar o nosso teste não sobreviveu a mutação e foi quebrado (logo não passou no teste para Bruxo 😂🤣)
Este foi um exemplo bem simples de como aplicar testes de mutação utilizando o Stryker. Como podemos ver o esforço nem é muito grande para passar utilizar essa ferramenta e o mais legal é que dá para você adiciona-la ao seu processo de build no AzureDevops, mas isso é assunto para outro post.