Перейти к основному содержимому

Почему именно модульные тесты

Перевод

Перевод (gpt) и адаптация статьи Unit testing best practices with .NET Core and .NET Standard by John Reese

Существует несколько причин использования модульных тестов.

image

Сокращение времени функционального тестирования

Функциональные (сценарные) тесты требуют значительных ресурсов. Обычно они включают запуск приложения и выполнение ряда шагов, которые вам (или другому сотруднику) необходимо пройти для проверки ожидаемого поведения. Тестировщик не всегда может знать все необходимые действия, и в таких случаях ему может понадобиться помощь более опытного коллеги. Время тестирования варьируется: оно может занять всего несколько секунд при проверке небольших изменений или растянуться на несколько минут при более крупных изменениях. Этот процесс нужно повторять при каждом внесении изменений в систему.

Модульные тесты, наоборот, выполняются за миллисекунды, запускаются одним нажатием кнопки и не требуют глубокого понимания всей системы.

Защита от регрессии

Регрессионные дефекты — это дефекты, которые появляются при внесении изменений в приложение. Обычно тестировщики проверяют не только новую функциональность, но и уже существующие функции, чтобы убедиться, что ранее реализованные возможности работают корректно.

С модульными тестами можно запускать весь набор тестов после каждой сборки или даже после изменения одной строки кода. Это дает уверенность в том, что новый код не нарушает существующую функциональность.

Исполняемая документация

Не всегда очевидно, что делает конкретный метод или как он себя ведет с определенными входными данными. Вы можете задаться вопросом: как метод работает, если передать ему пустую строку? А что если передать Неопределено?

Когда у вас есть набор модульных тестов с понятными названиями, каждый тест может четко объяснить ожидаемый результат для заданных входных данных. Кроме того, он проверяет, что метод действительно работает правильно.

Меньшая связность кода

Когда код слишком тесно связан, его трудно тестировать модульно. Без написания тестов связи в коде могут быть не такими очевидными.

Создание тестов для вашего кода естественным образом уменьшает его связность, поскольку иначе его было бы сложнее тестировать.

Характеристики хорошего юнит-теста

Быстрый: Не редкость, что у зрелых проектов есть тысячи юнит-тестов. Юнит-тесты должны выполняться за короткое время, в миллисекундах.

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

Повторяемый: Выполнение модульного теста должно быть согласовано с результатами, то есть всегда возвращает тот же результат, если вы ничего не измените между выполнением.

Самопроверяемый: Тест должен автоматически определять, прошел он или провалился, без вмешательства человека.

Соизмеримый: Написание юнит-теста не должно занимать непропорционально много времени по сравнению с тестируемым кодом. Если написание тестов занимает значительно больше времени, чем написание самого кода, следует рассмотреть более удобный для тестирования дизайн решения.

Устойчивость к рефакторингу: Тесты должны быть устойчивы к рефакторингу кода. Если производится рефакторинг, тесты не должны изменяться. Тогда успешное завершения всех модульных тестов после этапа рефакторинга поможет вам убедиться, что рефакторинг не испортил функционал приложения.

Простота поддержки: Тесты должны быть просты в поддержке. Этот пункт выполняется, если выполняется предыдущий пункт. Должно быть легко добавлять новые тестовые сценарии - поддержка тестов в актуальном состоянии не должна стать тяжелым грузом для команды разработки.

Кодовое покрытие

Высокий процент кодового покрытия часто ассоциируется с более высоким качеством кода. Однако само измерение не может определить качество кода. Установка слишком амбициозной цели по проценту кодового покрытия может оказаться контрпродуктивной. Представьте сложный проект с тысячами условных ветвлений и целью в 95% покрытия кода. Если в настоящее время проект поддерживает 90% покрытия, то затраты времени на учёт всех крайних случаев в оставшихся 5% могут оказаться огромными, а ценность этого может быстро снизиться.

Высокий процент кодового покрытия не является индикатором успеха и не подразумевает высокое качество кода. Это просто отражает количество кода, покрытого юнит-тестами. Для получения дополнительной информации смотрите раздел о покрытии кода в юнит-тестировании.