---
title: "Избыточная проверка"
type: "test-smell"
slug: "redundant-assertion"
url: "http://localhost:3000/ru/test-smells/redundant-assertion.md"
category: "Запахи утверждений"
description: "Избыточная проверка сравнивает значение с самим собой или с литералом, равным ему по построению, поэтому её исход предопределён, и она в принципе не может ни упасть, ни обнаружить регрессию."
---
# Избыточная проверка

> Избыточная проверка сравнивает значение с самим собой или с литералом, равным ему по построению, поэтому её исход предопределён, и она в принципе не может ни упасть, ни обнаружить регрессию.

## Signs and Symptoms

Проверка **избыточна**, когда её результат предрешён ещё до запуска тестируемого кода: ожидаемый и фактический операнды — это _одно и то же значение_, либо оба являются литералами, заведомо равными (или неравными). Каталог xUnit/Test Smells (Peruma и др.) определяет её как «тестовый метод, содержащий инструкцию проверки, в которой ожидаемый и фактический параметры совпадают», и отмечает, что такая проверка поэтому «либо всегда истинна, либо всегда ложна».

Как её распознать:

* `assertEquals`/`toBe`/`toEqual`, у которого оба аргумента — это **одно и то же выражение** или переменная.
* Булев литерал, проверяемый против самого себя, например `assertTrue(true)` или `expect(true).toBe(true)`.
* Сравнение, константность которого может доказать компилятор/линтер, вроде `expect(x === x).toBe(true)`.
* «Проверка на вменяемость», которая повторяет только что объявленную константу вместо того, чтобы задействовать систему.

```js
// Запах: исход предопределён, тестируемый код вообще не задействован
test('user is active', () => {
  expect(true).toBe(true);            // всегда проходит
  const status = 'active';
  expect(status).toBe('active');      // повторяет литерал, ничего не доказывает
  expect(user.id).toEqual(user.id);   // значение сравнивается с самим собой
});

```

Надёжный признак: можно полностью удалить продакшен-код, а проверка всё равно останется зелёной.

## Reasons for the Problem

**Почему это происходит**

* **Забытая отладка.** Каталог прямо отмечает, что этот запах «вносится разработчиками в отладочных целях, а затем забывается», — жёстко зашитая заглушка `assertTrue(true)`, доживающая до коммита.
* **Дрейф из-за копипаста / рефакторинга.** В обе стороны `assertEquals` подставлена одна и та же переменная, или тестируемое значение переименовали так, что ожидаемое и фактическое схлопнулись в один и тот же символ.
* **Тавтология по построению.** Значение проверяют против того же литерала, из которого его только что присвоили, вместо независимо выведенного ожидания.
* **Театр покрытия.** Проверку добавляют только ради соблюдения правила «в каждом тесте должна быть проверка», ничего осмысленного при этом не проверяя.

**Чем это вредит**

* **Ложная уверенность.** Тест навсегда зелёный и учитывается в размере набора и покрытии, но не проверяет ничего. Он не способен поймать регрессию и потому маскирует прорехи в страховочной сетке.
* **Надёжность бессмысленна.** Тест, который никогда не может упасть, даёт нулевой сигнал; тот, что всегда ложен, — мёртвый груз, который игнорируют или ставят `skip`.
* **Читаемость.** Читатели зря тратят силы, восстанавливая предполагаемое поведение по проверке, утверждающей тавтологию; тест больше не документирует требование.
* **Сопровождаемость.** Избыточные проверки накапливают шум, раздувают метрики и подрывают доверие к набору тестов, побуждая людей перестать внимательно читать проверки.

## Treatment

Замените тавтологию проверкой, которая связывает **независимо известное ожидаемое значение** с **фактическим результатом, выданным тестируемой системой**.

Шаги:

1. **Найдите проверку с предопределённым исходом** — один и тот же операнд с обеих сторон или два равных литерала.
2. **Определите настоящее намерение.** Какое поведение этот тест должен был проверять? Если никакое, то проверка (или весь тест) мертва и подлежит удалению.
3. **Проверяйте выход SUT, а не вход.** Подайте системе реальный вход и сравните вычисленный ею результат с жёстко зашитым, вычисленным вручную ожидаемым значением — а не с одним из её собственных входов/переменных.
4. **Держите ожидаемое и фактическое различными.** Убедитесь, что ожидаемый операнд — это намеренно написанная вами константа, а фактический операнд — возвращаемое значение тестируемого кода (заодно это устраняет родственный запах неверного порядка аргументов).
5. **Перезапустите со сломанной реализацией** (внесите мутацию), чтобы убедиться, что проверка действительно может упасть.

```js
// До — избыточно: исход предопределён
test('discount', () => {
  const total = 100;
  expect(total).toBe(100);          // повторяет литерал
  expect(applyDiscount).toBe(applyDiscount); // значение против самого себя
});

// После — осмысленно: известный вход -> независимо ожидаемый выход
test('applies a 10% discount', () => {
  expect(applyDiscount(100, 0.1)).toBe(90); // результат SUT против вручную вычисленного ожидания
});

```

Если заглушка вроде `assertTrue(true)` осталась от отладки — удалите её; если она замещала реальную проверку — напишите эту проверку.

## Detected by

- **sonar** `javascript:S5863` — Проверкам не следует передавать один и тот же аргумент дважды (https://rules.sonarsource.com/javascript/RSPEC-5863/)
- **sonar** `java:S5863` — Проверкам не следует передавать один и тот же аргумент дважды (https://rules.sonarsource.com/java/RSPEC-5863/)
- **eslint** `no-constant-binary-expression` — Запрет выражений, в которых операция не влияет на значение (помечает самосравнения / всегда истинные проверки вроде assert(a === a)) (https://eslint.org/docs/latest/rules/no-constant-binary-expression)
