Além do Fact com xUnit

Thiago Barradas
thiagobarradas
Published in
3 min readJun 23, 2019

Quando falamos de teste unitário em aplicações .NET, o xUnit é sem dúvidas a biblioteca preferida da maioria dos programadores. Porém, além de aplicar as boas práticas de teste, é necessário conhecer e usufruir dos recursos disponíveis da ferramenta, para que seus testes sejam limpos e facilmente manuteníveis.

Neste post, vamos abordar as principais funcionalidades do xUnit, muito além do tradicional Fact.

Fact

Para iniciar o papo sobre as funcionalidades do xUnit, nada melhor do que falar do seu recurso mais utilizado, o Fact.

Como o próprio nome induz, a ideia é testar um fato, algo “único” e objetivo. Esse é o recurso mais utilizado da biblioteca e pode facilmente atender todas as suas necessidades em um projeto de teste unitários.

Exemplo de Fact (xUnit)

Com essa estrutura é possível fazer qualquer tipo de teste, porém, quando a “lógica” do teste necessita ser a mesma, modificando apenas os parâmetros de entrada, a duplicação do código de teste é inevitável. Obviamente em alguns casos a “duplicação” pode ser aceitável e fazer sentido, mas em sua grande maioria, não tem sentido algum.

Exemplo de Fact (xUnit) com mudanças nas variáveis e duplicação da lógica.

Theory

Para resolver o problema apresentado anteriormente, o xUnit possui um recurso chamado Theory, o qual a lógica é a mesma para um conjunto de inputs e outputs diferentes. Reescrevendo os testes anteriores, ficaria algo como:

Exemplo do Theory (xUnit) com InlineData

Esse código seria executado duas vezes, uma para cada InlineData da anotação, passando os seus respectivos parâmetros. Nos resultados do teste, ele é subdividido na quantidade de testes que são executados permitindo a visualização de qual opção falhou. Usar Theory permite que você reaproveite o seu código de teste para diversos inputs/outputs diferentes, uma ótima opção para tornar mais fácil a manutenção dos testes em eventuais mudanças.

Em alguns casos, o seu InlineData pode ficar muito grande poluíndo os testes, ou, você pode necessitar passar objetos como parâmetro, mas como sabemos, não é possível instancia-los e passa-los via anotação em método.

Para resolver esse problema, vamos exemplificar o uso do MemberData.

Exemplo do Theory (xUnit) com MemberData

Neste exemplo, um pouco maior, conseguimos utilizar objetos como parâmetros e para isso necessitamos criar um IEnumerable<object[]> para fornecer os inputs necessários. Simplificando, é uma lista de objetos (que serão inputados no método de teste) dentro de outra lista (casos de teste).

Por mais que pareça mais complexo, o ideal é preferirmos objetos à muitos parâmetros na assinatura de um método em nossa arquitetura. Dado isso, utilizar essa estrutura pode ser a melhor opção.

Se o seu teste estiver ficando muito extenso, você pode optar por pôr mais um atributo, o ClassData, que é muito parecido com o MemberData, porém recebe uma classe que herda de IEnumerable<object[]>, assim fica mais fácil isolar os “modelos dos casos de testes” das implementações em si.

Exemplo do Theory (xUnit) com ClassData

Para finalizar, também podemos utilizar a forma “híbrida”, uma mesclagem entre o MemberData e o ClassData (mas na verdade é puramente o MemberData separando os parâmetros em uma class externa hehe).

Exemplo do Theory (xUnit) com MemberData “Híbrido”

Neste post vimos que além do Fact é possível reaproveitar bastante o código e a lógica dos testes com o uso da Theory e suas possíveis formas de input de dados. Não esqueça que testes também devem ser elegantes e seguir os princípios do Clean Code, afinal, se você tem todo o seu sistema testado e faz qualquer modificação, no mínimo um teste deveria quebrar e você deveria ajusta-lo a sua modificação, garantindo que o comportamento do sistema realmente teste todas as possibilidades e falhe quando alterações mínimas são feitas.

Bons testes e até a próxima! 👋

--

--

Thiago Barradas
thiagobarradas

Microsoft MVP, Elastic Contributor. Entusiasta de novas tecnologias e arquiteto de software na Stone. Cultuador do hábito de formar cabeças pensantes.