Наборы автоматизированных тестов -- замечательный
инструмент: они позволяют проводить инкрементальную разработку, определяя
регрессии в функциональности между двумя реализациями пользовательской истории.
Они облегчают развертывание, поскольку код сначала проверяется на машинах
разработчиков и CI-серверах, не давая ошибкам проникнуть в готовый продукт.
Однако, существует распространенное заблуждение о написании
тестов для каждого аспекта кода. Хотя для некоторых нефункциональных требований
это возможно, для остальных -- по-прежнему маловероятно.
Производительность
Тестирование производительности -- одна из сфер, где
автоматизация процесса генерации нагрузки играет важную роль, при условии ряда
поправок в выполнении тестов:
- тестируемая среда должна обладать теми же ресурсами, что и рабочая среда или вертикальное подмножество (по крайней мере, разделенный веб-сервер и база данных);
- нагрузка должна генерироваться с отдельной машины;
- базы данных, которые будут использоваться для тестов, должны быть соразмеримы с реальной рабочей средой, при этом, следует принять во внимание пониженную производительность машин.
Оценивать результаты тестов производительности нелегко, но
можно составить график последних прогонов и установить желаемый уровень,
который вы бы не хотели переступать (например, 10 секунд для произведения оплаты
или начала новой дискуссии на форуме).
Удобство сопровождения (и расширяемость)
Тестирование удобства сопровождения проекта является более
трудной задачей, чем тестирование производительности. В сущности, сопровождение
связано с расходами в будущем, поэтому их нельзя измерить. Можно только
надеяться найти цифры или другие "намеки" на низкую или высокую
стоимость сопровождения.
Генерирование метрик не представляет проблем, но как бы
сказал Гойко Аджич,
показатели покрытия, индексов, дублирования и т.п. являются отрицательными:
красный цвет свидетельствует о неисправностях; зеленый цвет не сообщает вам о
качестве кода.
Возьмите модульные тесты: известно, что они предоставляют
разработчикам более полную информацию о качестве кода. Возможность написать
модульные тесты с помощью нескольких строк кода для каждой части приложение
означает, что вы избегаете синглтонов, глобального состояния и скрытых
зависимостей, и что API созданных одиночных объектов можно использовать
отдельно, а объекты не взаимодействуют друг с другом.
Наличие арсенала модульных тестов предполагает только, что
вы избежали подобных проблем, но ведь существуют и другие. Все-таки, можно
произвести тщательно протестированные классы длиною в 100 строк, которые затем
разделяют на части, когда приходит пора реализовать следующее требование. На
первый план выходят знания предметной области вроде вероятности изменений и
отображение понятий реального мира в коде, что характерно для
предметно-ориентированного проектирования.
Безопасность
Хотя производительность можно протестировать, а модульные
тесты могут послужить первым средством против недостаточной способности к
сопровождению, когда речь идет о выполнении требований безопасности, мы не
знаем, что делать.
Как проверить, что нельзя выполнить массовые платежи с
помощью одной суммы денег? Или, что HTML-код нельзя внедрить в ваши формы? Как
и в случае с функциональными тестами, конкретный тест лишь гарантирует, что
определенная атака не "сработает" в форме. Он не гарантирует
отсутствие похожих атак. В то время, как проблемы функциональности проявляются
как ошибки, которые можно исправить, проблемы безопасности обойдутся вам
намного дороже.
Единственные известные мне два способа улучшить безопасность
приложения -- изучить распространенные атаки и схему их преодоления. Плюс,
пригласить для проверки ответственных экспертов по вопросам безопасности.
Параллелизм
Ошибки, связанные с параллелизмом, найти так же трудно, как
и прорехи в системе безопасности. Первые возникают при выполнении большого
количества различных процессов. Удачный прогон набора тестов -- даже при
одновременном выполнении множественных транзакций -- не гарантирует отсутствие
ошибок в готовом продукте.
Если вы столкнулись с гонками в коде, в лучшем случае вас
ждет периодическое непрохождение тестов, что заставит вас сомневаться и
увеличит сроки производства.
В худшем случае, тесты даже не выявят проблему и продолжат
проходить только потому, что вероятность возникновения состояния гонки после
нескольких сотен транзакций слишком низкая. Или они не представляют
существенной нагрузки, поскольку разбросаны по времени. По сути, устранение
ошибок параллелизма сводится к их воспроизведению.
Вывод
Тесты -- инструменты, помогающие нам улучшить качество ПО во
время разработки. Они наилучшим образом подходят для проверки функциональных
требований и ряда других свойств (производительность и способность к
сопровождению).
Но существуют критически важные свойства, которые ваши тесты
исправить не способны. Мы все еще можем обратиться за помощью к аудиту
безопасности, обзору кода и парному программированию.
Тесты -- это средство, а не цель.
Комментариев нет:
Отправить комментарий