Duplicate Assert.
Um único método de teste verifica a mesma condição mais de uma vez — repetindo uma asserção idêntica ou reverificando uma lógica equivalente — em vez de remover a verificação redundante ou separar casos distintos em seus próprios testes focados.
##Signs and Symptoms
Você vê a mesma asserção aparecer duas vezes (mesmo matcher, mesmos argumentos) em um único teste, ou vários blocos de asserção copiados e colados que diferem apenas nos valores literais e re‑testam o mesmo comportamento. Sinais reveladores:
- Uma linha de asserção literalmente idêntica aparece duas ou mais vezes no corpo.
- Muitas chamadas
expect(...)/assertEquals(...)exercitando a mesma condição com entradas diferentes, todas amontoadas em um único método cujo nome descreve apenas um único cenário. - Asserções remanescentes de depuração ("deixa eu também verificar X") que nunca foram removidas.
- O nome do teste (por exemplo,
testXmlSanitizer) não dá nenhuma pista sobre qual de suas muitas verificações falhou.
test('sanitizer accepts valid input', () => {
expect(isValid('plain text')).toBe(true);
expect(isValid('with spaces')).toBe(true);
expect(isValid('Fritz-box')).toBe(true); // "menos é válido"
expect(isValid('Fritz-box')).toBe(true); // <-- duplicata exata, não acrescenta nada
expect(isValid('<script>')).toBe(false);
});
A linha Fritz-box duplicada é o Duplicate Assert canônico; o smell mais amplo é que um único método agrupa silenciosamente muitas verificações da mesma condição sob um único nome.
##Reasons for the Problem
Por que acontece
- Copiar e colar. Um bloco de asserção é duplicado e os literais (ou nem isso) são alterados.
- Resíduo de depuração. Asserções extras adicionadas para investigar o comportamento são deixadas para trás.
- Agrupamento. Os desenvolvedores testam "um método" empilhando todos os casos em um único teste em vez de separá-los, produzindo verificações repetidas e quase idênticas.
Por que é prejudicial
- Falsa confiança. Uma asserção duplicada e verdadeiramente idêntica acrescenta zero cobertura — ela nunca pode falhar quando sua gêmea passa — e ainda assim faz o teste parecer mais completo do que é.
- Diagnóstico de falha difícil. Quando várias asserções com a mesma forma compartilham um único método, o relatório de falha aponta para o método, não para a entrada específica que quebrou. Pior ainda, um teste com configuração padrão para na primeira asserção que falha, de modo que as verificações duplicadas posteriores nunca são executadas — você corrige uma, executa de novo, esbarra na próxima (sobrepõe-se ao Assertion Roulette).
- Legibilidade ruim. O leitor não consegue dizer se a repetição é intencional (casos distintos) ou um erro (duplicata real), e o nome do teste documenta apenas uma de muitas condições.
- Custo de manutenção. Mude o comportamento sob teste e você terá que caçar e atualizar cada asserção duplicada; se errar uma, a suíte fica inconsistente.
##Treatment
- Exclua duplicatas exatas. Se uma asserção é byte a byte idêntica a outra no mesmo teste, remova-a — é peso morto, não cobertura.
- Parametrize casos equivalentes. Quando as "duplicatas" são na verdade a mesma condição com entradas diferentes, converta-as em um teste de tabela/parametrizado (
test.eachno Jest/Vitest,@ParameterizedTestno JUnit 5). Cada linha é reportada e nomeada separadamente, de modo que as falhas apontam exatamente para a entrada problemática. - Separe condições genuinamente diferentes em testes distintos, cada um com um nome que declare o que verifica (
aceita nomes de host com hífen,rejeita tags de script). - Nomeie pela intenção. O nome de um teste deve descrever um único comportamento; se você não consegue, isso é um sinal para separar.
// Antes — asserções duplicadas / agrupadas em um único teste opaco
test('isValid', () => {
expect(isValid('plain text')).toBe(true);
expect(isValid('with spaces')).toBe(true);
expect(isValid('Fritz-box')).toBe(true);
expect(isValid('Fritz-box')).toBe(true); // duplicata
expect(isValid('<script>')).toBe(false);
});
// Depois — uma única asserção, cada caso nomeado e reportado de forma independente
test.each([
['plain text', true],
['with spaces', true],
['Fritz-box', true], // menos é válido
['<script>', false], // rejeita marcação
])('isValid(%j) === %s', (input, expected) => {
expect(isValid(input)).toBe(expected);
});
A linha duplicada se foi, as entradas distintas estão explícitas, e uma falha nomeia o caso exato.