Testes baseados em propriedades em Swift: quando os testes comuns falham
Você já escreveu um teste unitário que passou com nota máxima, mas depois o aplicativo falhou com dados reais? Familiar, não é? Os testes clássicos baseados em exemplos (quando verificamos uma entrada e saída específicas) são bons, mas têm uma falha fundamental: eles verificam apenas o que nós mesmos inventamos. E se o bug viver nos limites dos valores permitidos, ou em uma combinação que simplesmente não nos ocorreu?
É aí que entram os testes baseados em propriedades em Swift. Esta é uma abordagem onde você descreve não casos específicos, mas propriedades (property) que devem ser verdadeiras para quaisquer dados de entrada. E um framework especial (por exemplo, SwiftCheck) gera centenas de valores aleatórios e verifica se sua propriedade não é violada. Se um bug for encontrado, o framework "minimiza" os dados de entrada — e você obtém o exemplo mais simples no qual tudo quebra.
Neste artigo, vamos explorar como implementar testes baseados em propriedades Swift em seu projeto, escrever exemplos de código reais e ver quais bugs podem ser capturados com essa abordagem. Vamos lá!
O que são testes baseados em propriedades e por que você precisa deles?
Imagine que você está testando uma função que ordena um array. Em vez de escrever 10 testes com arrays diferentes, você diz: "para qualquer array, após a ordenação, o comprimento não muda, e cada elemento é menor ou igual ao próximo". Isso é uma propriedade — um invariante que deve ser sempre verdadeiro.
Testes baseados em propriedades em Swift são ideais para:
- Verificar funções matemáticas (adição, divisão, arredondamento);
- Testar parsers e serializadores (serialização → desserialização deve retornar o original);
- Verificar lógica de negócios com muitas combinações;
- Encontrar regressões em valores limite.
O principal benefício: você encontra bugs cuja existência você nem suspeitava. E isso, convenhamos, é melhor do que confirmar o óbvio.
SwiftCheck — a principal ferramenta para testes baseados em propriedades em Swift
No mundo Swift, o framework mais popular para essa abordagem é o SwiftCheck. Ele traz ideias do Haskell (biblioteca QuickCheck) e se integra perfeitamente com o XCTest.
Para começar, adicione a dependência no seu Package.swift:
// swift-tools-version:5.9import PackageDescription
let package = Package( name: "MyProject", dependencies: [ .package(url: "https://github.com/typelift/SwiftCheck.git", from: "0.12.0") ], targets: [ .testTarget( name: "MyProjectTests", dependencies: ["SwiftCheck"]), ])Agora você pode escrever testes. Vamos analisar a sintaxe básica.
Primeiro teste baseado em propriedades: verificando a adição
Vamos escrever uma propriedade simples: "a adição é associativa". Para quaisquer números inteiros a + b + c deve ser igual a (a + b) + c.
import XCTestimport SwiftCheck
class MathPropertiesTests: XCTestCase { func testAdditionIsAssociative() { property("Adição é associativa") <- forAll { (a: Int, b: Int, c: Int) in return (a + b) + c == a + (b + c) } }}Ao executar o teste, ele executa 100 combinações aleatórias (por padrão). Se pelo menos uma falhar, o SwiftCheck mostrará os valores específicos. Observe que não especificamos nenhum número concreto! Testes baseados em propriedades Swift geram os dados automaticamente.
Verificação de transformação reversa (roundtrip)
Este é o padrão mais comum. Suponha que temos uma estrutura que é serializada em JSON. Propriedade: "após a serialização e desserialização, obtemos o mesmo ob