awesome-everything EN
↑ Обратно к восхождению

Инженерная практика

TDD: чтение кода и тестов

Суть Читай реальный тестовый код — первый падающий тест, хрупкий mock-тяжёлый тест, property и выжившего мутанта — и выбирай фикс или диагноз, который senior делает первым.
Высота — путь к senior
НольJuniorMiddleSenior
Ты на senior-высоте — в орбите
◷ 14 min

Качество тестов оценивается в файле теста, а не в отчёте о покрытии. Читай каждый сниппет как PR коллеги, затем выбери изменение, которое senior сделал бы первым.

Цель

Натренируй взгляд, с которым приходишь на реальное ревью: замечать тест, что проверяет структуру вместо поведения, писать падающий тест, который ведёт дизайн, формулировать property, что бьёт примеры, и читать, о чём говорит выживший мутант.

Сниппет 1 — первый падающий тест

// Ведём ещё не написанное правило возврата, тест-сначала.
test("refund for a fully-shipped order is rejected", () => {
  const order = anOrder({ status: "SHIPPED" });
  const result = refundPolicy.evaluate(order);
  expect(result.allowed).toBe(false);
  expect(result.reason).toBe("ALREADY_SHIPPED");
});
Викторина

До того как refundPolicy существует, что даёт написание этого теста первым и почему он хорошо сформирован?

Сниппет 2 — хрупкий тест

test("checkout charges the customer", () => {
  const tax = mock(TaxRule);          // чистый, наш собственный
  const gateway = mock(PaymentGateway); // сторонняя сеть
  when(tax.apply(100)).thenReturn(108);
  checkout.pay(cart, tax, gateway);
  verify(tax.apply(100)).once();      // проверяем, что вызов был
  verify(gateway.charge(108)).once();
});
Викторина

Сохраняющий поведение рефакторинг checkout делает этот тест красным, но реальный баг вычисления суммы однажды уехал с ним зелёным. В чём корневая причина?

Сниппет 3 — property

// fast-check: переписываем обкатанный CSV-парсер, oldParse — доверенный эталон.
fc.assert(fc.property(fc.string(), (raw) => {
  expect(newParse(raw)).toEqual(oldParse(raw)); // oracle property
}), { numRuns: 1000 });
Викторина

Какое утверждение об этом property верно?

Сниппет 4 — выживший мутант

// Продакшн-код под mutation testing:
function withinBudget(amount, limit) {
  return amount <= limit;   // Stryker мутировал в: amount < limit
}
// Полный набор всё равно прошёл после мутации. Мутант ВЫЖИЛ.
Викторина

Мутант '<=' → '<' выжил при 100% покрытия строк. О чём это говорит и какой фикс?

Итог

Каждый тест в этом юните читается одинаково. Первый падающий тест — это обратная связь по дизайну: он фиксирует интерфейс и проверяет наблюдаемый исход, поэтому переживает рефакторинги. Хрупкий тест over-mock’ает собственный чистый код: падает на рефакторинге и отгружает баги зелёным за застабленными результатами — используй реальные объекты и проверяй состояние. Oracle-property даёт доверенному эталону задавать корректность над сгенерированным входом и шринкует до минимального контрпримера. А выживший мутант — это именованный недостающий assertion, чаще всего граница, которую набор никогда не подал. Диагностируй по тесту, чини assertion, перезапускай для подтверждения, что мутант убит.

Продолжить восхождение ↑TDD: построй набор, который заметит баг
хоткеи развернуть
поиск
K
пред. пьеса
k
след. пьеса
j
тиры
t
это меню
?
sources3
expand
  1. 01
  2. 02
  3. 03

Trademarks belong to their respective owners. Editorial reference only.