Testes baseados em propriedades em C#: capture bugs que os testes unitários ignoram

Treinador Online de Python para Iniciantes

Aprenda Python facilmente sem sobrecarga teórica. Resolva tarefas práticas com verificação automática e escreva código diretamente no navegador.

Start Course

Seu teste unitário mente (e você sabe disso)

\n\n

Imagine: você escreveu 50 testes unitários, todos verdes, cobertura de 90%. Você está satisfeito. Mas, uma semana depois, a produção cai. Acontece que seu método SortArray() funciona perfeitamente para [1, 2, 3] e [3, 1, 2], mas falha em [int.MaxValue, -1, 0]. Familiar?

\n\n

O problema dos testes unitários clássicos é o viés do desenvolvedor. Você escreve testes para os dados que espera. Hackers, usuários reais e condições de contorno aleatórias seguem outras regras.

\n\n

É aqui que entram os testes baseados em propriedades em C# (ou property-based testing). Em vez de verificar "se A, então B", você descreve propriedades que devem ser sempre verdadeiras. E o framework gera centenas de entradas aleatórias e verifica suas afirmações.

\n\n

Neste artigo, vamos explorar como implementar testes baseados em propriedades em C# usando a biblioteca FsCheck, escrever exemplos reais e ver como eles capturam bugs que os testes comuns ignoram.

\n\n

O que são testes baseados em propriedades?

\n\n

Testes baseados em propriedades são uma abordagem onde você formula invariantes (propriedades) do seu programa. Por exemplo:

\n
    \n
  • "Após a ordenação, o comprimento do array não muda"
  • \n
  • "A ordem inversa da reversão de uma string resulta na string original"
  • \n
  • "A soma de dois números positivos é sempre positiva"
  • \n
\n\n

O framework (por exemplo, FsCheck) gera dezenas e centenas de entradas aleatórias e verifica se a propriedade é válida para todas. Se um contraexemplo for encontrado — o teste falha, e você obtém os valores específicos que quebraram o código.

\n\n

Ao contrário dos testes unitários, você não escreve Assert.AreEqual(3, Add(1,2)). Você escreve Assert(x + y == y + x) — e testa a comutatividade para milhares de pares de números.

\n\n

Diferença dos testes unitários comuns

\n\n\n\n\n\n\n\n
Testes unitáriosTestes baseados em propriedades
Verificam exemplos específicosVerificam leis gerais
Dados definidos pelo desenvolvedorDados gerados pelo framework
Ignoram casos de bordaExploram automaticamente os limites
Fáceis de lerExigem pensamento abstrato
\n\n

Biblioteca FsCheck: sua principal ferramenta

\n\n

No mundo C#, o padrão de facto para testes baseados em propriedades é o FsCheck (originalmente um port da biblioteca Haskell QuickCheck). Ele se integra com xUnit, NUnit e MSTest.

\n\n

A instalação é simples:

\n
dotnet add package FsCheck\ndotnet add package FsCheck.Xunit  // para integração com xUnit
\n\n

FsCheck é capaz de gerar dados aleatórios para tipos primitivos (int, string, float), listas, arrays, tuplas e até tipos personalizados (através de geradores customizados).

\n\n

Escrevendo nosso primeiro teste baseado em propriedades em C#

\n\n

Vamos começar com algo simples: verificar se a operação de adição de números inteiros é comutativa.

\n\n
using FsCheck;\nusing FsCheck.Xunit;\n\npublic class AdditionTests\n{\n    [Property]\n    public bool Commutative_Addition(int x, int y)\n    {\n        return x + y == y + x;\n    }\n}
\n\n

Execute o teste. O FsCheck gerará 100 pares aleatórios de int (por padrão) e verificará a propriedade. Se nenhum contraexemplo for encontrado — o teste fica verde. Se tivéssemos errado (por exemplo, escrito x - y == y - x), o teste falharia com um exemplo específico: (5, 3) — porque 5 - 3 != 3 - 5.

\n\n

Analisando o código

\n
    \n
  • [Property] — atributo que informa ao FsCheck que este é um teste baseado em propriedades.
  • \n
  • O método retorna bool — se retornar false, o teste falha.
  • \n
  • Parâmetros int x, int y — o FsCheck substituirá automaticamente por valores aleatórios.

Blogs

Book Recommendations