Testes baseados em propriedades em JavaScript: capturando bugs que você não procurou

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

E se os testes se escrevessem sozinhos? Conhecendo os testes baseados em propriedades

\n\n

Você já escreveu um teste unitário, executou-o, recebeu a marca verde e, um mês depois, encontrou um bug na mesma função? Familiar? Os testes unitários clássicos são como verificar se sua carteira não está vazia, olhando apenas para uma nota. Você verifica um cenário específico, um conjunto específico de dados de entrada. E se eu lhe dissesse que existe uma maneira de fazer o computador inventar milhares de cenários diferentes e verificar se seu código não quebra?

\n\n

Isso não é ficção científica. São os testes baseados em propriedades em JavaScript (ou teste baseado em propriedades). Em vez de escrever "se passar 2 e 3, obtemos 5", você descreve uma propriedade da sua função: "para quaisquer dois números, o resultado da soma será um número que é sempre maior ou igual a cada uma das parcelas". E o ambiente de teste gera centenas de pares aleatórios de números, verificando essa afirmação.

\n\n

Neste artigo, vamos explorar como funciona o teste baseado em propriedades, como ele difere dos testes comuns e como implementá-lo em seu projeto usando a excelente biblioteca fast-check. Você verá como é fácil encontrar bugs "de fronteira" que você nem pensaria em procurar.

\n\n

Por que os testes unitários comuns nem sempre salvam?

\n\n

Vamos direto ao ponto. Suponha que você tenha uma função que ordena um array de números em ordem crescente:

\n\n
function sortNumbers(arr) {\n  return arr.slice().sort((a, b) => a - b);\n}
\n\n

Você escreve um teste unitário:

\n\n
test('ordena o array [3, 1, 2]', () => {\n  expect(sortNumbers([3, 1, 2])).toEqual([1, 2, 3]);\n});
\n\n

O teste está verde. Você está feliz. Mas e se o array tiver null? Ou undefined? Ou números muito grandes? Ou um array com 10.000 elementos? Você não vai escrever um teste para cada um desses casos. Mas o teste baseado em propriedades em JavaScript vai.

\n\n

Em vez de listar exemplos, você descreve invariantes (propriedades) que devem ser sempre verdadeiras:

\n
    \n
  1. O comprimento do array ordenado é igual ao comprimento do array original.
  2. \n
  3. Cada elemento do array original está presente no array ordenado.
  4. \n
  5. Para qualquer índice i, é verdade que arr[i] <= arr[i+1].
  6. \n
\n\n

São exatamente essas propriedades que o teste de propriedades verificará.

\n\n

Biblioteca fast-check: sua ajudante em testes aleatórios

\n\n

No mundo JavaScript, a principal ferramenta para testes baseados em propriedades é a fast-check. Ela é capaz de gerar dados aleatórios de qualquer tipo: números, strings, arrays, objetos, datas — e até estruturas complexas.

\n\n

A instalação é simples:

\n
npm install fast-check --save-dev
\n\n

Agora vamos escrever nosso primeiro teste baseado em propriedades para a função sortNumbers. Usaremos o framework Jest, mas o fast-check funciona com qualquer executor de testes.

\n\n
const fc = require('fast-check');\n\ntest('a ordenação preserva o comprimento do array', () => {\n  fc.assert(\n    fc.property(fc.array(fc.integer()), (arr) => {\n      const sorted = sortNumbers(arr);\n      return sorted.length === arr.length;\n    })\n  );\n});
\n\n

O que está acontecendo aqui? fc.array(fc.integer()) é um gerador que cria arrays aleatórios de inteiros aleatórios. fc.property pega esse gerador e verifica a afirmação (nossa função arrow) em 100 (por padrão) conjuntos diferentes de dados. Se pelo menos um teste falhar — fc.assert lançará um erro e mostrará um contraexemplo.

\n\n

Adicionando mais propriedades

\n\n

Uma propriedade é bom, mas três é melhor. Vamos verificar se, após a ordenação, o array está realmente ordenado:

\n\n
test('a ordenação retorna um array ordenado', () =>                

Blogs

Book Recommendations