Давайте немного вернемся к началу и поразмышляем на тему собственно юнита (модуля). Что это такое? Какие тесты еще можно называть модульным, а какие уже не являются таковыми, потому что уже тестируют несколько юнитов?
Обратимся к классику (Мартин Фаулер) :
“Объектно-ориентированный подход рассматривает класс как юнит, процедурные или функциональные подходы могут рассматривать одну функцию как юнит. Но на самом деле команда решает, что такое юнит исходя из их понимания системы и ее тестирования" (вольный перевод, а статья кстати хорошая, почитайте)
Хмм, получается, что нет строгого определения, что считать юнитом?
Да, но есть нюансы.
Вы знали, что существует 2 школы
Лондонская и Детройтская (она же Чикагская).
Что самое забавное, когда говорят про недостатки юнит-тестов, то чаще всего указывают на проблемы, которые возникают при лондонском подходе.
Чем же они отличаются?
Одно из отличий - это как раз определение размеров юнита.
Лондонская школа определяет юнит, как класс/функцию и предполагает изоляцию SUT (system under test) от всего того, с чем он взаимодействует через test doubles (тест-дублеры, на старославянском - моки, что неправильно, но все привыкли). То есть, мы проверяем строго то, как работает SUT ориентируясь на его публичный интерфейс и поведение нужное нам для реализации пользовательского сценария. А все его внешние зависимости замокированы. Это как раз и и приводит к тому самому “цементированию” кода тестами, затрудняющего его модификацию.
В Детройтской школе юнит может быть любого размера, от класса до компонента из нескольких связанных между собой классов, при написании тестов избегают использования тест-дублеров и ориентируются в первую очередь на проверку состояния SUT.
Считается, что это "кунг-фу" несет риск появления кода, который потом не будет использоваться (нарушение принципа YAGNI), потому что мы не отталкиваемся от пользовательского сценария.
Но на моей практике, при сильном желании и достаточном умении, накостылить лишнего кода можно при любом подходе.
Мне больше импонирует детройтский подход, в первую очередь из-за низкой связности тестов с кодом (в сравнении с лондонским вариантом).
Итого: если отбросить в сторону #holywar со школами, то юнитом можно считать минимальное логическое объединение кода ориентированного на реализацию конкретной функциональности, которое мы хотим и можем проверить отдельно от других таких объединений.
При этом проектировать код нужно так, чтобы иметь возможность вносить нужную нам для тестов реализацию его зависимостей.
Полезные ссылки
• Are You Chicago Or London When It Comes To TDD?
• London vs Chicago
• London and Detroit schools of unit tests (похоже недоступно из РФ, есть копия из кэша)
Заключение
#unit_testing #test_automation