Asserções e [Theory]
ResumoAsserções (
Assert.*) verificam o resultado esperado.[Theory]com[InlineData]roda o mesmo teste com vários conjuntos de dados, evitando duplicação.
1. Objetivos de Aprendizagem#
- Usar as asserções mais comuns do xUnit.
- Escrever testes parametrizados com
[Theory]/[InlineData]. - Verificar exceções com
Assert.Throws.
2. Pré-requisitos#
- xUnit e AAA (tópico 15.1).
3. Conceito#
Asserções declaram o que deve ser verdade. Se falharem, o teste falha:
Assert.Equal(esperado, real)— igualdade.Assert.True/False(condição).Assert.Null/NotNull(obj).Assert.Contains/Empty— coleções.Assert.Throws<TEx>(() => ...)— exceções.
[Theory] transforma um teste em parametrizado: cada [InlineData(...)] é um caso. O porquê: cobrir muitos cenários (limites, valores válidos/inválidos) sem copiar e colar o teste.
4. Mão na Massa#
4.1. Setup#
dotnet new xunit -n Catalog.Tests2
4.2. Implementação Passo a Passo#
- Asserções variadas:
using Xunit;
public class AssercoesTests
{
[Fact]
public void Assercoes_Comuns()
{
var nomes = new[] { "Mouse", "Teclado" };
Assert.Equal(2, nomes.Length);
Assert.Contains("Mouse", nomes);
Assert.All(nomes, n => Assert.False(string.IsNullOrEmpty(n)));
}
}
[Theory]com múltiplos casos:
public class CalculadoraPreco
{
public decimal ComDesconto(decimal preco, decimal pct) => preco * (1 - pct);
}
public class DescontoTheory
{
[Theory]
[InlineData(100, 0.1, 90)]
[InlineData(200, 0.5, 100)]
[InlineData(50, 0, 50)]
public void ComDesconto_Casos(decimal preco, decimal pct, decimal esperado)
{
var calc = new CalculadoraPreco();
Assert.Equal(esperado, calc.ComDesconto(preco, pct));
}
}
- Verificando exceção:
[Fact]
public void ComDesconto_PercentualInvalido_Lanca()
{
var calc = new CalculadoraPreco();
Assert.Throws<ArgumentOutOfRangeException>(() => Validar(calc, 1.5m));
static void Validar(CalculadoraPreco c, decimal pct)
{
if (pct > 1) throw new ArgumentOutOfRangeException(nameof(pct));
}
}
4.3. Executando#
dotnet test
5. Exemplo Completo#
O [Theory] acima cobre três cenários de desconto num único método — se a lógica quebrar em qualquer caso, o relatório aponta exatamente qual [InlineData] falhou.
6. Boas Práticas e Armadilhas#
| Faça | Evite |
|---|---|
[Theory] para variações do mesmo comportamento | Copiar e colar [Fact] quase idênticos |
Asserção específica (Assert.Equal) com mensagem clara | Assert.True(a == b) (falha sem detalhe do valor) |
Testar caminho de erro com Assert.Throws | Testar só o caminho feliz |
Atenção
Assert.Equalcompara por valor para tipos apropriados; para objetos complexos, garanta uma comparação significativa (ex.: records comparam por valor, classes por referência salvo override).
7. Segurança e Produção#
- Testar caminhos de erro (entradas inválidas, exceções) é o que protege a API de comportamentos inesperados sob dados maliciosos ou malformados.
8. Exercícios#
- Fácil: escreva uma
[Theory]com três casos de soma. - Médio: use
Assert.Throwspara validar uma exceção. - Desafio: cubra os limites (0, máximo, inválido) de um método com
[Theory].
9. Resumo#
Asserções verificam resultados; [Theory] + [InlineData] parametrizam casos, e Assert.Throws valida exceções. Prefira asserções específicas e teste também os caminhos de erro.
10. Próximos Passos#
Último tópico: isolar dependências com mocks (Moq).
11. Referências#
- xUnit — Fact vs Theory
- Microsoft Learn — Boas práticas de testes unitários
- Microsoft Learn — Testes com dados (data-driven)