Подкожный тест (Subcutaneous test)

Впервые упоминание встречается в 2010 году у Jimmy Bougard в блоге: ”В то время как модульный тест фокусируется на мелкомасштабном дизайне, подкожный тест не касается дизайна, а вместо этого проверяет основные входы и выходы системы в целом”, затем в докладе Matt Davies and Rob Moore - “Microtesting - How We Set Fire To The Testing Pyramid While Ensuring Confidence”, а позже и в презентации Daniel Lafeir and Michael Lawrie. Термин «подкожный» означает автоматизированный тест непосредственно под слоем пользовательского интерфейса. В приложении MVC это будут тесты для всего, что находится непосредственно под контроллером. Для веб-службы все, что находится ниже ендпоинта (endpoint).

Идея состоит в том, что самый верхний уровень в приложении не выполняет никакой реальной бизнес-логики, а просто соединяет внешние интерфейсы с базовыми службами. Как подчеркивает Martin Fowler в своем сообщении о подкожном тестировании, такие тесты особенно полезны при попытке выполнить функциональные тесты, когда вы хотите реализовать сквозной сценарий, избегая при этом некоторых трудностей, связанных с тестированием через сам пользовательский интерфейс:

  • UI-тесты медленные. От этого никуда не деться. Их можно запускать параллельно, допиливать напильником и делать чуть-чуть быстрее, но они останутся медленными;

  • UI-тесты нестабильные. Отчасти потому, что они медленные. А еще потому, что Web-браузер и интерфейс пользователя не были созданы для того, чтобы ими управлял компьютер (в настоящее время данный тренд меняется, но не факт, что это хорошо);

  • UI-тесты - это наиболее сложные тесты в написании и поддержке. Они просто тестируют слишком много. (Это усиливается тем фактом, что, зачастую, люди берут «ручные» тест-кейсы и начинают их автоматизировать как есть, без учета разницы в ручном и автоматическом тестировании);

  • Нам говорят, что, якобы, UI-тесты эмулируют реального пользователя. Это не так. Пользователь не будет искать элемент на странице по ID или XPath локатору. Пользователь не заполняет форму со скоростью света, и не «упадет» если какой-то элемент страницы не будет доступен в какую-то конкретную миллисекунду. И даже теперь, когда браузеры разрабатываются с учетом того, что браузером можно программно управлять - это всего-лишь эмуляция, даже если очень хорошая;

  • Кто-то скажет, что некоторый функционал просто нельзя протестировать иначе. Я скажу, что если есть функционал, который можно протестировать только UI тестами (за исключением самой UI логики) - это может быть хорошим признаком архитектурных проблем в продукте.

Таким образом определение можно сформулировать так: “Если модульный тест тестирует наименьший тестируемый компонент кода приложения, то подкожный тест представляет собой единый рабочий процесс (workflow), который можно идентифицировать и протестировать в коде приложения. Подкожное тестирование рассматривает рабочий процесс как тестируемую единицу”.

Стоит помнить, что это не прямая замена автоматизации тестирования через UI, а просто более целенаправленное тестирование функциональности на нужном уровне приложения. Это позволяет команде создавать более совершенные сквозные тесты с использованием существующего кода, фреймворка и / или библиотек, доступных для внешнего приложения. Основная цель этого вида тестирования - уменьшить нестабильность теста и сосредоточиться на функциональности. Это позволяет группе различать функциональные сбои из-за проблем с кодом и сбои приложений из-за проблем совместимости или проблем с внешними зависимостями. Поскольку подкожные тесты можно запускать с той же тестовой средой, что и модульные тесты, они не имеют доступа к внутреннему коду или вызовам API во время работы. Изоляция этих тестов и использование имитирующих инструментов, которые могут имитировать вызовы API и заглушки для различных взаимодействий служб, могут дать целенаправленную, изолированную оценку функциональности во внешнем стеке. Такое тестирование функциональности позволяет сделать любую автоматизацию через браузер и пользовательский интерфейс более легкими. Это означает, что традиционные тесты пользовательского интерфейса могут быть очень минимальными и проверять только то, что связи работают между уровнями приложения. Вместо использования дорогостоящих тестов графического интерфейса и пользовательского интерфейса для получения информации о функциональности они могут быть поверхностными проверками работоспособности или дымовыми тестами. Избегая использования автоматизации пользовательского интерфейса, утверждающей ожидание чего-то функционально работающего, тесты могут утверждать, правильно ли приложение обменивается данными на своих уровнях интеграции.

Поскольку при подкожном тестировании используются все компоненты на странице, создание интегрированных тестов, которые тестируют только несколько компонентов, или тестирование одного компонента на уровне модуля может не потребоваться. Модульные тесты могут быть нацелены на более сложную логику, а не пытаться протестировать всю логику вокруг одного компонента, тестирование базовой логики облегчает нагрузку на модульное тестирование. Подкожное тестирование использует ту же структуру тестирования (например, Jest), что и модульные тесты. Это сохраняет функциональные тесты внутренними и ближе к коду, что дает команде больше шансов на более быструю обратную связь и более быструю настройку теста, чем тестовая среда, поддерживаемая отдельно. Это означает, что командам не нужно выполнять дополнительную работу по сопровождению нескольких фреймворков, репозиториев, а иногда и языков для выполнения функционального тестирования пользовательского интерфейса. Теперь, когда подкожное тестирование позволяет проводить функциональное тестирование кода, а не через пользовательский интерфейс, любые тесты пользовательского интерфейса могут быть сокращены до небольшой части того, что было необходимо ранее. UI-тесты можно использовать как дымовые тесты. Таким образом они могут доказать, что приложение и все его уровни находятся в работоспособном состоянии связи.

Поскольку подкожные тесты ориентированы на поведение высокого уровня (high-level behavior), а не на дизайн, они идеально подходят для стратегий тестирования на основе сценариев (scenario-based testing strategies), таких как BDD или паттерн Testcase Class per Fixture.

К сожалению, наряду со всеми плюсами subcutaneous подхода мы можем получить и снижение покрытия (coverage), в частности glue code (Связующий код - программный код, который служит исключительно для «склеивания» разных частей кода, и при этом не реализует сам по себе никакую иную прикладную функцию). Насколько важна\существенна потеря покрытия в данном случае? Зависит от ситуации. Мы потеряли немного glue code, который может быть (а может и не быть) важным (рекомендую в качестве упражнения определить, какой код потерялся). Оправдывает ли данная потеря покрытия введения тяжеловесного тестирования на уровне UI? Это тоже зависит от ситуации. Мы можем, например:

  • Добавить один UI-тест для проверки glue code, или

  • Если мы не ожидаем частых изменений glue code - оставить его без автотестов, или

  • Если у нас есть какой-то объем «ручного» тестирования - есть отличный шанс, что проблемы с glue code будут замечены тестировщиком, или

  • Придумать что-то еще (тот же канареечный релиз, Canary deployment)

Один из способов избежать потери покрытия - “Feature Tests Model

Источники:

Last updated