Но настоящая причина, по которой эти тесты нельзя назвать избыточными, заключается в том, что тестирование не является их главной функцией. Тот факт, что они что-то проверяют, вторичен. Модульные и приемочные тесты прежде всего являются документами и лишь потом – тестами. Их главная цель – формальное документирование архитектуры, структуры и поведения системы. Автоматическая проверка архитектуры, структуры и поведения чрезвычайно полезна, но истинной целью является именно документирование.
Графические интерфейсы и другие сложности
Графический интерфейс трудно определить заранее. Теоретически это возможно, но редко удается сделать хорошо. Дело в том, что эстетика – предмет субъективный, а следовательно, переменчивый. Разработчики любят
Это обстоятельство усложняет написание приемочных тестов для графических интерфейсов. Задача решается таким проектированием системы, при котором графический интерфейс можно было бы рассматривать как API, а не как набор кнопок, ползунков, таблиц и меню. На первый взгляд кажется странно, но в действительности речь идет просто о качественном проектировании.
В области проектирования программных систем существует принцип, называемый принципом единственной обязанности (SRP, Single Responsibility Principle). Он гласит, что при проектировании следует разделять аспекты системы, которые могут изменяться по разным причинам, и группировать вместе те аспекты, которые изменяются по одним и тем же причинам. Графические интерфейсы не являются исключением.
Макет, формат и схема выполнения операций в графическом интерфейсе могут меняться по эстетическим причинам и по соображениям эффективности, но базовая функциональность графического интерфейса остается неизменной. Таким образом, при написании приемочных тестов для графического интерфейса следует пользоваться базовыми абстракциями, которые изменяются относительно редко.
Например, на странице могут находиться несколько кнопок. Вместо создания тестов, имитирующих нажатия кнопок по их положению на странице, следует предусмотреть возможность имитации нажатий с идентификацией по именам. Еще лучше, если у каждой кнопки будет уникальный идентификатор. При написании теста намного приятнее выбирать кнопку с идентификатором ok_button, чем кнопку в столбце 3 строки 4 таблицы элементов.
Выбор интерфейса для тестирования
И все же лучше писать тесты, которые активизируют функции тестируемой системы через API, а не через графический интерфейс. При этом должен использоваться тот же API, который используется графическим интерфейсом. В этом нет ничего нового: специалисты в области проектирования десятилетиями говорили нам, что графический интерфейс нужно отделять от бизнес-логики.
Тестирование через графический интерфейс всегда создает проблемы (если вы не ограничиваетесь тестированием одного лишь графического интерфейса). Дело в том, что графический интерфейс с большой вероятностью изменится, а это делает тесты весьма непрочными. Когда каждое изменение интерфейса нарушает работу тысячи тестов, вы либо начинаете отказываться от тестов, либо перестаете изменять графический интерфейс. Ни один из этих вариантов хорошим не назовешь. Итак, пишите тесты бизнес-логики так, чтобы они проходили через API, находящийся за графическим интерфейсом.
Некоторые приемочные тесты определяют поведение самого графического интерфейса. Естественно, такие тесты должны проходить через графический интерфейс. Однако они не тестируют бизнес-логику, а следовательно, не требуют ее связывания с графическим интерфейсом. По этой причине на время тестирования самого графического интерфейса лучше изолировать его от бизнес-логики и заменить последнюю заглушками.
Ограничьтесь минимальным объемом тестов графического интерфейса. Они слишком непрочны из-за изменчивости графического интерфейса. Чем больше у вас тестов графического интерфейса, тем меньше вероятность того, что они останутся неизменными.
Непрерывная интеграция
Проследите за тем, чтобы все модульные и приемочные тесты запускались несколько раз в день в механизме непрерывной интеграции. Этот механизм должен инициироваться вашей системой управления исходным кодом. Каждый раз, когда кто-то вносит в базу новый модуль, механизм непрерывной интеграции должен инициировать сборку с последующим запуском всех тестов в системе. Результаты запуска должны рассылаться всем участникам группы.
Стоп-сигнал