Перейти к содержимому

Навыки

chimera-prove-the-test-discriminates

Регрессионный тест, падения которого вы никогда не видели, — это догадка. Сломайте код обратно и убедитесь, что тест краснеет, прежде чем его коммитить.

ПаттернПроисхождение: cleanСостояние: activev0.1.0 · Apache-2.0

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

Когда это вспоминается

  • написал регрессионный тест
  • починил баг и добавил тест
  • тест зелёный, катим
  • добавляю тест после правки

Ценность обычно лежит в разделах «Избегать» и «Проверить». «Делать» — это раздел, который пишут все.

Текст карточки выше — перевод. Английский оригинал — это то, что импортирует командная строка, что читает агент во время работы и что подтверждает хеш ниже.

Повод

Вы починили баг и написали тест, чтобы он не вернулся. Тест проходит. Это всё свидетельство, которое у вас есть, и оно ровно такое же, каким было бы, если бы тест вообще ничего не утверждал про этот баг.

Особенно остро это, когда тест написан после починки: тогда единственный код, против которого он вообще работал, — код, где бага уже нет. Меньше это относится к тесту, написанному первым и красным, в цикле TDD, — его падение вы уже видели, в чём и состоит весь смысл цикла.

Это не относится к тесту на действительно новое поведение, где никакого «до» для отката не существует. Там различающая проверка другая: удалите новую реализацию и убедитесь, что тест падает на её отсутствии, а не на баге.

Делать

  1. Определите ровно ту правку, которая и есть починка, — hunk, а не коммит. Если починка — одно изменённое сравнение, то откатывать вы будете именно это сравнение.
  2. Откатите её. git stash для починки или руками верните ту одну строку в сломанный вид.
  3. Запустите только новый тест: pytest tests/test_thing.py::test_the_regression -x.
  4. Прочтите падение. Падать должно ваше утверждение, с сообщением о поведении, — не SyntaxError, не ошибка сбора тестов, не ImportError из наполовину откаченного файла. Это красное не по той причине, и о тесте оно не доказывает ничего.
  5. Верните починку (git stash pop) и убедитесь, что тот же тест теперь проходит.
  6. Занесите факт в docstring теста: что было откачено и как выглядело падение. Следующему, кто тронет этот тест, нужно знать, что его вообще прогоняли против бага.

Избегать

Утверждать то, что верно в обоих мирах. Классическая форма:


result = parse_config(raw)
assert result is not None
assert "timeout" in result

Баг был в том, что timeout возвращался строкой "30" вместо целого 30. Оба утверждения держатся в любом случае. Различает то, что изменилось:

# RIGHT — fails against the buggy code
assert parse_config(raw)["timeout"] == 30
assert isinstance(parse_config(raw)["timeout"], int)

Также не откатывайте, закомментировав целую функцию или удалив импорт, чтобы «упало побыстрее». Это даёт красный прогон, который случился бы для любого теста в файле, и потому не говорит ничего про этот тест. Откат обязан быть починкой и только починкой.

И избегайте близкого промаха, когда тест доходит до починенного кода путём, которым production никогда не ходит, — это другой сбой, и карточка про него называется chimera-test-the-wiring-not-the-class.

Проверить

Один двоичный вопрос: видели ли вы лично, как этот тест печатает падение, вызванное его собственным утверждением, против непочиненного кода?

Если да — вы закончили. Если ответ «он бы упал», вы не проверили ничего: эта фраза — предсказание, произведённое тем же рассуждением, что написало тест.

Механически:

git stash                 # remove the fix
pytest tests/test_x.py::test_regression   # MUST be red, on your assertion
git stash pop             # restore
pytest tests/test_x.py::test_regression   # MUST be green

Красное, потом зелёное, оба наблюдались лично, — иначе тест не доказан.

Риск

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

Настоящая опасность этой карточки — забытый откат. Проделывать этот танец в грязном рабочем дереве — верный способ закоммитить заново сломанную строку вместе с её собственным регрессионным тестом, при зелёном наборе, потому что починку вы вернули не в тот файл. Запускайте git diff перед коммитом, каждый раз.

И различающий тест хорош ровно настолько, насколько вы поняли баг. Он доказывает, что тест ловит этот откат. Он не доказывает, что вы починили первопричину, а не симптом, и считать прогон «красное, потом зелёное» доказательством этого — заявление больше, чем позволяет свидетельство.

Как применить

Карточка — это данные. Склонируйте репозиторий и импортируйте её по пути: всё, что приходит по сети, считается заражённым и удерживается до одобрения — это и есть желаемое поведение, и поэтому здесь нет установщика в одну строку.

git clone https://github.com/brcampidelli/chimera-agent.git
chimera skills-import chimera-agent/skills/chimera-prove-the-test-discriminates/SKILL.md

Целостность

SHA-256 файла в опубликованном виде. Импортёр может проверить, что полученное совпадает с показанным на этой странице.

90d4bf00eb67055008527ee372153b2637fa2feea601ed6760997eda239f0b76

Читать карточку в репозитории