ConstructiCat Logo
CodeBust.
Browse section ▾

Igualdade Sensível.

Um teste verifica o comportamento comparando a representação em string de um objeto (toString(), JSON.stringify(), HTML renderizado) com um literal de string esperado, acoplando o teste a detalhes incidentais de formatação em vez dos valores que realmente importam.

##Signs and Symptoms

Você reconhece a Igualdade Sensível quando o lado real de uma asserção serializa um objeto em texto e seu lado esperado é um literal de string que agrupa muitos campos com separadores, aspas, colchetes e espaços em branco.

Sinais reveladores:

  • O valor real vem de .toString(), String(x), um template literal, JSON.stringify(...), wrapper.html(), el.outerHTML ou de um snapshot de um blob serializado.
  • O valor esperado é uma string literal longa (muitas vezes colada de uma execução anterior que falhou) e você não consegue dizer de relance qual parte dela é o que está sendo testado.
  • O teste quebra em mudanças que não afetam o comportamento: chaves reordenadas, espaços em branco adicionados/removidos, precisão numérica, formato de data, locale, fuso horário ou ordem de iteração de Map/Set/objeto.
// Comparando uma forma serializada com um literal de string
expect(JSON.stringify(user)).toBe('{"name":"Bob","age":30}');

// Verificando a saída de toString()
expect(order.toString()).toBe('Order[id=7, total=42.00, items=2]');

// Comparando o HTML renderizado completo com um literal
expect(wrapper.html()).toBe('<div class="card"><h2>Bob</h2><span>30</span></div>');

// Comparação de string sensível a locale/fuso horário
expect(d.toString()).toBe('Mon Jun 15 2026 00:00:00 GMT+0000 (UTC)');

##Reasons for the Problem

Por que acontece

  • É rápido e fácil. Como observam van Deursen et al. em Refactoring Test Code, é rápido calcular um resultado real, convertê-lo em string e compará-lo com um literal de string que representa o valor esperado — muitas vezes o literal é apenas copiado de uma execução que falhou. As ferramentas de snapshot tornam isso ainda mais tentador.
  • O objeto não tem uma igualdade significativa (equals/deep matcher) configurada, ou o grafo de objetos é grande, então despejá-lo em uma string parece mais simples do que verificar campo a campo.

Por que prejudica

  • Fragilidade / falsas falhas. A string carrega muitos detalhes irrelevantes — vírgulas, aspas, espaços, ordenação de chaves, precisão de ponto flutuante, locale, fuso horário, ordem de iteração de coleções. Sempre que o formato de toString()/serialização muda, testes não relacionados começam a falhar mesmo que o comportamento esteja correto. Essa é uma causa clássica de Teste Frágil.
  • Manutenibilidade. Uma única mudança de formatação ou de biblioteca força edições em muitos testes, e o literal esperado gigante é tedioso de atualizar e fácil de errar sutilmente.
  • Legibilidade / intenção obscurecida. Um valor esperado em forma de muro de texto esconde o que está realmente sendo verificado; um revisor não consegue ver o único campo que importa para o teste.
  • Falsa confiança. Um blob convertido em string pode passar pelos motivos errados (dois estados distintos que serializam para o mesmo texto), e induz os desenvolvedores a regravar o literal/snapshot quando há falha, sem verificar se o novo valor está de fato correto.
  • Instabilidade (flakiness). Strings sensíveis a locale, fuso horário e ordenação fazem com que os resultados dependam do ambiente em que o teste é executado.

##Treatment

Verifique os dados, não a sua renderização.

  1. Compare valores estruturados com igualdade profunda (deep equality) em vez de igualdade de string (toEqual/toStrictEqual), que é independente de ordem e de espaços em branco para objetos.
  2. Verifique apenas os atributos relevantes com matchers parciais (toMatchObject, expect.objectContaining), para que uma mudança de formatação em outro lugar não possa quebrar o teste.
  3. Faça o parse, não a comparação por string. Quando você recebe um payload serializado (por exemplo, um corpo JSON de API), faça o parse de volta para uma estrutura e compare estruturas.
  4. Introduza um método de igualdade/comparação no objeto (a refatoração que van Deursen et al. recomendam) e verifique a igualdade de objetos em vez da igualdade de toString().
  5. Se você precisar comparar a saída serializada, canonize-a primeiro — ordene as chaves, fixe locale/fuso horário, defina a precisão numérica — e prefira um snapshot revisado a um literal inline colado à mão.
  6. Para testes de DOM/componentes, consulte de forma semântica (Testing Library getByRole, toHaveTextContent) em vez de comparar o HTML completo.
// Antes — Igualdade Sensível
expect(JSON.stringify(user)).toBe('{"name":"Bob","age":30}');

// Depois — igualdade estrutural (independente de ordem de chaves / espaços em branco)
expect(user).toEqual({ name: 'Bob', age: 30 });

// Depois — verifica apenas o campo em teste
expect(user).toMatchObject({ age: 30 });
// Antes — comparação por string de um payload de API
expect(res.text).toBe('{"id":7,"total":42}');

// Depois — compara estruturas já parseadas
expect(JSON.parse(res.text)).toEqual({ id: 7, total: 42 });