Ценным, но трудно достижимым свойством тестов является устойчивость — тест должен падать только если что-то важное пошло не так. Противоположное свойство автотестов легче заметить: хрупкий, или хлипкий тест — тот, который падает не из-за реальных проблем, которые могут привести к багу на проде, а потому что тест хрупкий по внутренним причинам — он неправильно спроектирован. Некорректные сообщения об ошибках, изменение порядка заголовков метаданных в веб-запросе, или порядка обращений к замоканной зависимости — приводят к хрупкости.
Выразительные («экспрессивные») тестовые API — мощный инструмент в борьбе с хрупкими тестами, перегруженными деталями. Например тест, написанный через простой IsSquare(output)
, более выразителен (и менее хрупок), чем тест, написанный с излишними деталями, например JsonEquals(.width = 42, .length = 42)
, если размер квадрата не имеет значения. Подобные выразительные конструкции могут включать неупорядоченное сопоставление элементов хэш-контейнеров, сравнение метаданных для фотографий и логов активности в обрататываемых объектах, и т.п.
В качестве примера рассмотрим плохой тестовый код на C++:
absl::flat_hash_set<int> GetValuesFromConfig(const Config&); TEST(ConfigValues, DefaultConfigsArePrime) { // Note the strange order of these values. BAD CODE, DON’T DO THIS! EXPECT_THAT(GetValuesFromConfig(Config()), ElementsAre(29, 17, 31)); }
Зависимость от упорядочивания хэшей делает этот тест хрупким, препятствуя улучшению тестируемого API. Важнейшей частью исправления вышеупомянутого кода было создание лучшего API для тестов, который позволил более эффективно выражать важные свойства. Таким образом, мы добавили UnorderedElementsAre
в тестовый фреймворк GoogleTest (здесь подробнее о GoogleTest) и рефакторизовали хрупкие тесты:
TEST(ConfigValues, DefaultConfigsArePrimeAndOrderDoesNotMatter) { EXPECT_THAT(GetValuesFromConfig(Config()), UnorderedElementsAre(17, 29, 31)); }
Видя хрупкие тесты, легко сказать: «Тот, кто это написал, все сделал неправильно! Почему эти тесты такие плохие?». Но выгоднее видеть в этих хрупких тестах — сигнал, что хорошие API для тестирования отсутствуют или требуют доработки.
Хрупкость может указывать на то, что автор теста не имел доступа, или не знал о существовании тестовых API, которые могли бы эффективнее показывать важные свойства, которые тест должен был проверить. Без хороших инструментов часто получаются тесты, зависящие от несущественных деталей, и это делает их хрупкими.
Если ваши тесты хрупкие, ищите способы сузить количество «золотых» (golden diff) тестов, которые сравнивают точное расположение пикселей или вывод логов. Изучите подход «выразительные API» и научитесь работать с ними. Обращайтесь с запросами о фичах к владельцам вышестоящих систем.
Если вы поддерживаете библиотеки инфраструктуры и не можете внести изменения из-за хрупкости, подумайте о том, чего не хватает вашим пользователям, и инвестируйте в выразительные API для тестов.