ConstructiCat Logo
CodeBust.
Browse section ▾

Asserção Redundante.

Uma asserção redundante compara um valor consigo mesmo ou com um literal que é igual por construção, de modo que seu resultado é fixo e ela nunca pode realmente falhar ou detectar uma regressão.

##Signs and Symptoms

Uma asserção é redundante quando seu resultado é decidido antes mesmo de o código sob teste rodar — os operandos esperado e real são o mesmo valor, ou ambos são literais sabidamente iguais (ou diferentes). O catálogo xUnit/Test Smells (Peruma et al.) a define como "um método de teste que contém uma instrução de asserção na qual os parâmetros esperado e real são os mesmos," e observa que a asserção, portanto, "é sempre verdadeira ou sempre falsa."

Como identificá-la:

  • Um assertEquals/toBe/toEqual cujos dois argumentos são a mesma expressão ou variável.
  • Um literal booleano afirmado contra si mesmo, por exemplo assertTrue(true) ou expect(true).toBe(true).
  • Uma comparação que o compilador/linter consegue provar ser constante, como expect(x === x).toBe(true).
  • Uma "verificação de sanidade" que reafirma uma constante que você acabou de declarar, em vez de exercitar o sistema.
// Smell: o resultado é fixo, o código sob teste nunca é envolvido
test('user is active', () => {
  expect(true).toBe(true);            // sempre passa
  const status = 'active';
  expect(status).toBe('active');      // reafirma o literal, não prova nada
  expect(user.id).toEqual(user.id);   // valor comparado consigo mesmo
});

Um indício confiável: você pode excluir totalmente o código de produção e a asserção ainda passa verde.

##Reasons for the Problem

Por que acontece

  • Resíduo de depuração. O catálogo observa explicitamente que este code smell "é introduzido por desenvolvedores para fins de depuração e depois esquecido" — um espaço reservado assertTrue(true) embutido no código que sobrevive até o commit.
  • Cópia e cola / desvio em refatoração. Uma variável é substituída em ambos os lados de um assertEquals, ou um valor sob teste é renomeado de forma que o esperado e o real colapsam no mesmo símbolo.
  • Tautologia por construção. Afirmar um valor contra o literal a partir do qual ele acabou de ser atribuído, em vez de contra uma expectativa derivada de forma independente.
  • Teatro de cobertura. Uma asserção é adicionada apenas para satisfazer regras de "todo teste deve fazer asserção", sem verificar nada significativo.

Por que prejudica

  • Falsa confiança. O teste fica permanentemente verde e conta para o tamanho da suíte e a cobertura, mas não verifica nada. Ele não pode pegar uma regressão, então mascara lacunas na rede de segurança.
  • Confiabilidade sem sentido. Um teste que nunca pode falhar fornece sinal zero; um que é sempre falso é peso morto que acaba ignorado ou marcado com skip.
  • Legibilidade. Os leitores desperdiçam esforço reconstruindo o comportamento pretendido a partir de uma asserção que afirma uma tautologia; o teste não documenta mais um requisito.
  • Manutenibilidade. Asserções redundantes acumulam ruído, inflam métricas e corroem a confiança na suíte, incentivando as pessoas a parar de ler as asserções com atenção.

##Treatment

Substitua a tautologia por uma verificação que vincule um valor esperado conhecido de forma independente ao resultado real produzido pelo sistema sob teste.

Passos:

  1. Identifique a asserção de resultado fixo — o mesmo operando em ambos os lados, ou dois literais iguais.
  2. Determine a real intenção. Qual comportamento este teste deveria verificar? Se nenhum, a asserção (ou o teste inteiro) está morta e deve ser removida.
  3. Faça asserção sobre a saída do SUT, não sobre a entrada. Alimente o sistema com uma entrada real e compare seu resultado calculado a um valor esperado fixo, calculado à mão — não a uma de suas próprias entradas/variáveis.
  4. Mantenha esperado/real distintos. Garanta que o operando esperado seja uma constante que você escreveu de propósito e que o operando real seja o valor de retorno do código sob teste (isso também corrige o code smell relacionado de ordem errada de argumentos).
  5. Reexecute com a implementação quebrada (mute-a) para confirmar que a asserção realmente consegue falhar.
// Antes — redundante: o resultado é fixo
test('discount', () => {
  const total = 100;
  expect(total).toBe(100);          // reafirma o literal
  expect(applyDiscount).toBe(applyDiscount); // valor vs ele mesmo
});

// Depois — significativo: entrada conhecida -> saída esperada de forma independente
test('applies a 10% discount', () => {
  expect(applyDiscount(100, 0.1)).toBe(90); // resultado do SUT vs expectativa calculada à mão
});

Se um espaço reservado como assertTrue(true) ficou da depuração, exclua-o; se ele estava no lugar de uma verificação real, escreva essa verificação.

##Detected by

  • sonar javascript:S5863Asserções não devem receber duas vezes o mesmo argumento
  • sonar java:S5863Asserções não devem receber duas vezes o mesmo argumento
  • eslint no-constant-binary-expressionProíbe expressões em que a operação não afeta o valor (sinaliza autocomparações / asserções sempre verdadeiras como assert(a === a))