Testes baseados em propriedades em PHP: quebrando o código mais rápido do que você escreve

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

Introdução: por que seus testes mentem e você acredita neles

\n\n

Imagine: você escreveu 50 testes unitários, cobriu todos os if-else, executou no CI — tudo verde. Uma semana depois, a produção cai com o erro "Division by zero". Como? Se os testes passaram! Familiar?

\n\n

O problema dos testes unitários clássicos (exemplares, com números específicos) é que eles verificam o que você já sabe. Você escolhe argumentos que, na sua opinião, levarão a um erro. Mas a mente do programador é previsível: todos escrevemos testDivideByZero e esquecemos testDivideByNegativeZero ou testDivideByVeryLargeFloat.

\n\n

É aqui que entram os testes baseados em propriedades em PHP — um método que não verifica cenários específicos, mas prova propriedades do seu código para milhares de entradas aleatórias. Hoje, vamos abordar como implementar essa abordagem no seu projeto PHP, usando Eris e PHPUnit. Você aprenderá a encontrar bugs que os testes comuns ignoram e por que isso não é mágica, mas engenharia.

\n\n

O que são testes baseados em propriedades? (e por que não é aleatório)

\n\n

Um teste unitário comum se parece com isso: assert(2 + 2 === 4). Você verifica uma única afirmação específica. O teste baseado em propriedades (PBT) funciona de forma diferente: você formula uma propriedade — uma afirmação que deve ser verdadeira para quaisquer dados de entrada válidos.

\n\n

Exemplo de propriedade para uma função de soma:

\n
    \n
  • Comutatividade: a + b === b + a para quaisquer números.
  • \n
  • Idempotência: aplicar a função repetidamente não altera o resultado.
  • \n
  • Invariância: o resultado é sempre positivo (se essa for a propriedade).
  • \n
\n\n

O PBT gera centenas de valores aleatórios (incluindo valores limite, zero, negativos, NaN) e verifica se a propriedade não é violada. Se um contraexemplo for encontrado — o teste falha com os dados de entrada específicos que causaram a falha. Você não recebe apenas "teste falhou", mas um bug reproduzível.

\n\n

Em PHP, essa tecnologia é especialmente útil devido à tipagem dinâmica: você nunca sabe qual tipo realmente chegará à função.

\n\n

Ferramentas para testes baseados em propriedades em PHP

\n\n

A principal ferramenta é a biblioteca Eris (github.com/giorgiosironi/eris). Ela se integra com o PHPUnit e fornece geradores de dados aleatórios. Uma alternativa são os recursos nativos do PHPUnit 10+ (mas ainda são imaturos). Usaremos o Eris, pois é uma ferramenta madura e documentada.

\n\n

Instalação via Composer:

\n
composer require --dev giorgiosironi/eris
\n\n

Também será útil o Faker para gerar estruturas complexas (email, nomes, endereços).

\n\n
composer require --dev fakerphp/faker
\n\n

Escrevendo o primeiro teste baseado em propriedades: quebrando a ordenação

\n\n

Suponha que temos uma função sortArray() que usa quicksort. Vamos escrever uma propriedade: "o array após a ordenação não deve conter elementos menores que o anterior".

\n\n
use Eris\\TestTrait;\nuse Eris\\Generator\\IntegerGenerator;\nuse PHPUnit\\Framework\\TestCase;\n\nclass SortTest extends TestCase\n{\n    use TestTrait;\n\n    public function testSortedArrayProperty(): void\n    {\n        $this->forAll(\n            Generator\\seq(Generator\\int())\n        )->then(function (array $input) {\n            $sorted = sortArray($input);\n            for ($i = 0; $i < count($sorted) - 1; $i++) {\n                $this->assertLessThanOrEqual(\n                    $sorted[$i + 1],\n                    $sorted[$i],\n                    "Array não está ordenado: " . json_encode($sorted)\n                );\n            }\n        });\n    }\n}\n
\n\n

Execução

Blogs

Book Recommendations