Найти тему
(java || kotlin) && devOps

Рецензия на Шаблоны тестирования xUnit

Всем привет!

По следам отличной книги Владимира Хорикова Принципы юнит-тестирования, см https://t.me/javaKotlinDevOps/50, решил погрузится в тему и прочитать еще и классику жанра - "Шаблоны тестирования xUnit. Рефакторинг кода тестов" https://www.litres.ru/dzherard-mesarosh/shablony-testirovaniya-xunit-refaktoring-koda-t-48637685/

К слову, на английском книга выложена в виде сайта со списком паттернов тестирования http://xunitpatterns.com/

По сути книга и является большим справочников паттернов. Автор - человек дотошный: любую типовую практику, используемую для написания тестов он вынес в шаблон с подробным описанием истории возникновения, вариантов реализации и примеров, мотивирующих на использование шаблонов.

Вот примеры шаблонов из книги, на которые хотел бы обратить внимание:

1) 5 видов моков http://xunitpatterns.com/Mocks,%20Fakes,%20Stubs%20and%20Dummies.html - от Dummy object, который ничего не возвращает, не делает и не проверяет, а нужен лишь для передачи как параметр, до Fake Object - облегченной реализации боевой логики, без обращений во внешние системы и БД. Видел ссылки на эти 5 типов в других статьях и книгах.

2) Test Utility Method - одна из базовых практик при рефакторинге тестов, вынесение повторяющего кода в отдельные методы. Это может быть код настройки системы, код проверки результата с assert-ми и код очистки ресурсов. Очень полезная штука, с какого-то момента после рефакторинга вынесенных методов для их переиспользования мы получаем некий тестовый язык, по сути свой DSL, и это без всяких Cucumber-ов и прочих BDD. http://xunitpatterns.com/Test%20Utility%20Method.html

3) Delegated Setup http://xunitpatterns.com/Delegated%20Setup.html - продолжение тесы выделения вспомогательного кода в методы. Лушче это делать в виде обычного метода, а не @BeforeEach, т.к. это улучшает читаемость теста.

4) Minimal Fixture http://xunitpatterns.com/Minimal%20Fixture.html - использование минимально возможной настройки системы для прохождения теста. Суть в том, что если сделать один большой метод @BeforeEach для кучи тестов - тесты станут хрупкими, т.к. изменяя один функционал и модифицируя @BeforeEach для него легко поломать другие использующего его тесты. Да и скорость запуска страдает

5) Guard Assertion http://xunitpatterns.com/Guard%20Assertion.html - многие использовали не подозревая, что это паттерн) Суть в том, что перед запуском теста проверить, что тестовое окружение находится в правильном состоянии, если нет - упасть не доходя до самого теста

6) Generated Value http://xunitpatterns.com/Generated%20Value.html - генерация случайного уникального значения для каждого теста. Особенно актуально для тестов с БД, но вообще говоря актуально всегда, т.к. генеруя случайные значение есть вероятность при очередном запуске поймать редкую ошибку, зависящую от входных данных.

7) Humble object http://xunitpatterns.com/Humble%20Object.html - идея в том, чтобы разделить бизнес-логику и контекстно-зависимую логику, и в первую очередь тестировать первую. Примеры: сохранение в БД и управление транзакцией - если их разделить, то тестировать работу с БД можно с использованием отката транзакции в тесте, что сильно упрощает очистку БД. Еще - бизнес-логика и создание нового процесса для ее выполнения. Бизнес-логику можно тестировать синхронно, что сильно ускоряет тесты. А для кода создания нового процесса можно сделать 1-2 теста и запускать их не при каждом прогоне.

8) Assertion Message http://xunitpatterns.com/Assertion%20Message.html - базовая вещь, про них в 99% случаев забывают. Это нормально, если название теста говорящее и в тем один assert. И ненормально в других случаях.

Есть в книге и антипаттерны:

1) цепочка тестов http://xunitpatterns.com/Chained%20Tests.html - цепочка зависящих друг от друга тестов

2) общая тестовая конфигурация http://xunitpatterns.com/Shared%20Fixture.html - тестовая конфигурация, которая настраивается один раз и используется несколькими тестами без очистки\пересоздания. Это нормально при ручном тестировании, т.к. трудоемкость настройки большая и есть человек, запускающий тесты, который может разобраться в причине падения. И плохо для модульных или автотестов, т.к. ручного вмешательства не должно быть.

Итого: многие шаблоны из книги очевидны для опытного разработчика, но в их описании можно найти новую для себя информацию. Читать книгу новичку точно не стоит, т.к во вступительных главах, очень много ссылок на шаблоны, и если ты их не использовал и не понимаешь по названию что это такое - утонешь в дебрях ссылок. Как книгу-справочник или книгу для упорядочивания опыта в тестировании - можно рекомендовать. Читать от корки до корки не нужно, нужно прочитать как раз первые главы, которые объясняют как писать тесты и глянуть заинтересовавшие вас шаблоны. Сравнивая с "Припципами юнит-тестирования" - с них стоит начать, и читать "шаблоны" только если не хватило информации из "принципов".

#unittests #books