Teste Verboso.
Um teste que usa muito mais código do que precisa para declarar seu cenário, soterrando a única relação de causa e efeito que verifica sob boilerplate de configuração, dados irrelevantes e asserções campo a campo.
##Signs and Symptoms
Você não consegue dizer o que um teste prova num relance, mesmo que nada de complicado esteja acontecendo — a intenção está afogada em volume. Sinais comuns:
- O método de teste é longo (o catálogo de Test Smells usa um limite aproximado de >30 linhas) ou ultrapassa uma tela ao rolar.
- Um grande bloco
arrangeconstrói objetos campo a campo, boa parte irrelevante para o comportamento sob teste. - Muitos literais hard-coded sem ligação óbvia entre as entradas e as saídas asseridas.
- O resultado é verificado com uma pilha de asserções de campo único em vez de uma comparação significativa.
- Lendo as asserções, você não consegue mapear facilmente qual entrada causou qual valor esperado.
test('places an order for a returning customer', () => {
const address = new Address();
address.street = '123 Main St';
address.city = 'Springfield';
address.zip = '00000'; // irrelevante para este teste
address.country = 'US';
const customer = new Customer();
customer.id = 42;
customer.firstName = 'Ada';
customer.lastName = 'Lovelace';
customer.email = 'ada@example.com';
customer.address = address;
customer.createdAt = new Date('2020-01-01'); // ruído
const product = new Product();
product.sku = 'SKU-1';
product.name = 'Widget';
product.price = 9.99;
const cart = new Cart();
cart.add(product, 2);
const order = orderService.placeOrder(customer, cart);
expect(order.status).toBe('CONFIRMED'); // as únicas linhas que importam
expect(order.lineItems.length).toBe(1);
expect(order.lineItems[0].sku).toBe('SKU-1');
expect(order.lineItems[0].quantity).toBe(2);
expect(order.total).toBe(19.98);
expect(order.customerId).toBe(42);
});
Cerca de 25 linhas de construção protegem uma asserção de duas linhas sobre totais e status.
##Reasons for the Problem
Por que acontece
- Construção inline com campos obrigatórios. Construir objetos reais por meio de construtores/setters obriga você a fornecer dados com os quais o teste não se importa, só para fazer o código compilar e rodar. Meszaros observa que o nível de detalhe necessário para tornar um teste executável pode deixá-lo "tão verboso a ponto de ser difícil de entender".
- Crescimento por copiar e colar. Um teste começa pequeno e, então, cada novo cenário é criado copiando o anterior e ajustando um valor, de modo que o ruído se acumula.
- Sem auxiliares de construção compartilhados. Sem Creation Methods, builders ou fixtures, todo teste reescreve o grafo de objetos completo.
- Dados hard-coded e verificação campo a campo. Escrever literais por toda parte e asserir cada propriedade parece "minucioso", mas multiplica a contagem de linhas.
Por que isso prejudica
- Legibilidade. O Teste Verboso é uma variação do Teste Obscuro — o catálogo até lista "Teste Obscuro" (Obscure Test) como seu alias. O leitor não consegue enxergar a relação de causa e efeito entre fixture e resultado, que é todo o propósito de um teste baseado em exemplo.
- Manutenibilidade. Um teste com mais de 30 linhas tende a carregar "várias responsabilidades", então uma pequena mudança no código de produção repercute em muitas linhas em muitos testes. Configuração inline em massa também gera duplicação.
- Falsa confiança. Testes longos e ruidosos escondem bugs à vista de todos: um literal incorreto ou uma asserção fora do lugar é fácil de passar despercebido, e a verbosidade faz os revisores lerem por cima. O volume parece rigoroso sem provar mais nada.
- Confiabilidade. Quanto mais estado irrelevante um teste fixa, mais provável é que ele quebre por razões alheias à sua intenção (superespecificação), produzindo falhas frágeis e de baixo sinal.
##Treatment
Empurre o ruído para fora do corpo do teste, de modo que apenas as variáveis que conduzem o comportamento permaneçam visíveis. Movimentos concretos (todos do xUnit Test Patterns):
- Extraia Creation Methods / use um builder. Substitua a construção inline de objetos por um auxiliar de nome evocativo que forneça padrões sensatos; passe apenas os valores com os quais o teste realmente se importa (Parameterized Creation Method). Isso elimina tanto o boilerplate quanto a Informação Irrelevante.
- Atribua valores padrão aos dados irrelevantes dentro do auxiliar, sinalizando "esses valores não afetam o resultado".
- Substitua as verificações campo a campo por um Expected Object (
toEqual/toMatchObject) ou por uma Custom Assertion / método de verificação que nomeie o conceito sendo verificado. - Verifique um comportamento por teste. Se um único teste é longo porque exercita vários resultados (um Eager Test), divida-o.
- Parametrize testes verbosos quase idênticos com
test.each/it.eachem vez de copiar e colar.
// antes — veja Sinais e Sintomas (≈30 linhas de setup + 6 asserções)
// depois
test('confirms the order and charges line-item total', () => {
const customer = aCustomer(); // Creation Method, com padrões
const cart = aCartWith(aProduct({ price: 9.99 }), 2); // apenas a entrada relevante
const order = orderService.placeOrder(customer, cart);
expect(order).toMatchObject({ // Expected Object, não campo a campo
status: 'CONFIRMED',
total: 19.98,
});
});
O cenário agora se lê em segundos: um cliente compra duas unidades de um produto de US$ 9,99 → o pedido é confirmado com um total de US$ 19,98. Os auxiliares (aCustomer, aProduct, aCartWith) são utilitários compartilhados e testados, então o ruído vive em um único lugar em vez de em cada teste.
Proteção: limite o tamanho da função de teste e a contagem de asserções no seu linter (veja os detectores) para que os testes não voltem silenciosamente a crescer e se tornar Testes Verbosos.
##Detected by
- eslint max-lines-per-function — Impõe um número máximo de linhas por função — sinaliza corpos de teste que excedem o limite configurado, a medida central de um Teste Verboso.
- eslint max-statements — Impõe um número máximo de instruções em um bloco de função — limita o quanto um único teste (uma callback de arrow/função) pode fazer.
- sonar S138 — Funções não devem ter linhas de código demais — aplica-se a funções de teste; sinaliza métodos de teste grandes demais e com múltiplas responsabilidades (RSPEC-138).
- eslint-jest jest/max-expects — Impõe um número máximo de chamadas expect() por teste (padrão 5) — captura a faceta de pilha de asserções dos testes verbosos/ansiosos.
- eslint-vitest vitest/max-expects — Impõe um número máximo de chamadas expect() por teste (padrão 5) — equivalente do Vitest para jest/max-expects.