Возможно, вы также слышали о паттерне «Given-When-Then», похожем на AAA. Этот паттерн также рекомендует разбить тест на три части:
• Given — соответствует секции подготовки (arrange); • When — соответствует секции действия (act); • Then — соответствует секции проверки (assert). В отношении построения теста эти два паттерна ничем не отличаются. Единственное отличие заключается в том, что структура «Given-When-Then» более понятна для не-программиста
Тесты не должны проверять единицы кода (units of code). Вместо этого они должны проверять единицы поведения (units of behavior) — нечто имеющее смысл для предметной области, а в идеале — нечто такое, полезность которого будет понятна бизнесу. Количество классов, необходимых для реализации такой единицы поведения, не имеет значения. Тест может охватывать как несколько классов, так и только один класс или даже всего один маленький метод
Тесты — это тоже код. Их следует рассматривать как часть кодовой базы, предназначенную для решения конкретной проблемы: обеспечения правильности приложения. Юнит-тесты, как и любой другой код, также подвержены ошибкам и требуют сопровождения
Невозможно добиться цели юнит-тестирования, просто добавив в проект больше тестов. Необходимо учитывать как пользу этих тестов, так и затраты на их сопровождение.
тесты требуют начальных вложений, и иногда весьма значительных. Но в долгосрочной перспективе они окупаются, позволяя проекту расти на более поздних стадиях. Разработка большинства нетривиального программного обеспечения без помощи тестов практически невозможна
Сама возможность покрытия кода тестами — хороший критерий определения качества этого кода, но он работает только в одном направлении. Это хороший негативный признак — он выявляет низкокачественный код с относительно высокой точностью. Если вдруг обнаружится, что код трудно протестировать, это верный признак того, что код нуждается в улучшении. Плохое качество обычно проявляется в сильной связности (tight coupling) кода; это означает, что части кода недостаточно четко изолированы друг от друга, что в свою очередь создает сложности с их раздельным тестированием
Большинство моих юнит-тестов тратило изрядную долю времени на настройку ожиданий и плетение сложной паутины зависимостей — и все это для проверки правильности всего трех строк кода в моем контроллере. Я не мог сформулировать, что именно не так с моими тестами, но было стойкое ощущение того, что это не нормально.
Я видел тесты, которые покрывали сложные алгоритмы и не делали ничего, кроме повторной реализации этих алгоритмов в секции подготовки. По сути они были копией рабочего кода
Интерфейсы с одной реализацией не являются абстракциями и способствуют слабой связности не более чем конкретные классы, реализующие эти интерфейсы. Подлинные абстракции открываются, не изобретаются. Открытие по определению происходит тогда, когда абстракция уже существует, но еще не имеет четкого места в коде. Таким образом, чтобы интерфейс был полноценной абстракцией, он должен иметь как минимум две реализации