Как стать автором
Обновить

Всё, что вы хотели знать про пирамиду тестирования, но не знали как спросить

Уровень сложностиСредний
Время на прочтение10 мин
Количество просмотров23K

Как родилась пирамида тестирования

Пирамида тестирования — это модель, впервые описанная Майком Коном в книге “Succeeding with Agile: Software Development Using Scrum” в 2009 году. Майк является одним из авторов метода разработки программного обеспечения Scrum.

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

  • модульные (юнит-) тесты;

  • сервисные тесты;

  • тесты пользовательского интерфейса (UI).

Пирамида тестирования Майка Кона
Пирамида тестирования Майка Кона

Важно отметить, что пирамида тестирования Майка Кона – это пирамида автоматизации тестирования, и предполагается, что на всех трех уровнях тестирования должны писаться автотесты.

Фундаментом пирамиды служат юнит-тесты, так как их проще всего разработать. Тесты пользовательского интерфейса, напротив, сложны в написании и очень легко ломаются при незначительных изменениях какого-либо компонента в интерфейсе, поэтому они находятся на вершине пирамиды. К сервисным тестам Майк относит тестирование сервисов отдельно от пользовательского интерфейса, но при этом он берет во внимание, что существуют архитектуры не только сервис-ориентированные. Для любой архитектуры на этом уровне пирамиды должны находиться тесты, которые проверяют, что делает приложение в ответ на некоторый ввод данных через программный интерфейс.

Почему пирамида Кона включает в себя только автоматизированные тесты, и значит ли это, что ручные тесты не нужны? Здесь стоит обратиться к истокам карьеры Майка и обнаружить, что он начинал свой путь в роли программиста, работающего на C и C++. Уволившись из большой корпорации, где был специальный отдел тестирования, он попал в маленький стартап из 8 человек, среди которых не было ни единого тестера, и за качество продукта приходилось отвечать ему и его коллеге программисту. Нехватка денег у компании на тестеров вынудила разработчиков отставить панику и создать собственный комплект инструментов и методов автоматизированного тестирования приложения. Тестировщиков в конце концов наняли, но к тому моменту абсолютно все программисты того стартапа пришли к пониманию, что за качество продукта должна отвечать команда целиком и делать это непрерывно.

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

Современная пирамида тестирования

Майк старался донести понимание важности интеграции тестирования в разработку до всех компаний-разработчиков программного обеспечения, где ему удалось поработать. В 2024 году уже вряд ли кому-то придется это объяснять, но как правильно реализовать тестирование известно не всем. Помочь в вопросе может не что иное, как созданная Коном абстракция. Она позволит командам определить стратегию тестирования на проекте и выстроить иерархию тестов.

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

Тем не менее, пирамида Кона служит хорошим базисом для разработки собственной модели на проекте. Слои пирамиды можно дополнять и адаптировать под любой контекст и архитектуру, определяя ответственные роли для каждого уровня. Чтобы построить собственную модель, нужно:

  1. идентифицировать проблемные места;

  2. определить необходимые виды тестов;

  3. определить необходимое тестовое покрытие;

  4. определить стоимость каждого из видов тестов с учетом используемых технологий, бизнес-домена, архитектуры и существующего «legacy»;

  5. определить ответственные роли для каждого уровня.

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

Пример современной пирамиды тестирования
Пример современной пирамиды тестирования

При проектировании и реализации пирамиды тестирования важно придерживаться следующих ключевых принципов:

  1. тест должен быть на том же уровне, что и тестируемый объект (например, модульный (юнит-) тест должен быть на модульном уровне, нельзя запускать на API уровне тест, который проверяет минимальную единицу кода);

  2. тесты более высокого уровня не тестируют логику более низкого уровня (например, в E2E тестах не должна проверяется логика обработки граничных значений);

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

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

Рассмотрим детальнее каждый из уровней современной пирамиды.

Юнит- (модульное) и компонентное тестирование

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

Юнит- (модульное) тестирование фокусируется на наименьшей единице кода и проектируется самим фронтенд- или бекенд-разработчиком. Модульные тесты выполняются на уровне функций, методов и классов, и должны следовать принципу “one assertion per test” (одно утверждение на тест). Некоторые зависимости в модуле могут заменяться на заглушки и моки (главное различие между заглушками и моками заключается в том, что в одном случае мы управляем состоянием, а в другом - поведением), обеспечивая таким образом высокую скорость исполнения тестов.

Обычно такие тесты пишутся и запускаются разработчиком после написания кода приложения, тем не менее в гибких методологиях разработки написание модульных тестов может предшествовать написанию кода приложения. К примеру, парадигма разработки на основе тестирования (test-driven development, TDD) подразумевает написание автоматизированных юнит-тестов перед написанием кода приложения. Она основывается на повторении коротких циклов: сначала пишется тест, покрывающий желаемое изменение, затем пишется код, который позволит пройти тест, и под конец проводится рефакторинг нового кода. Так или иначе, хороший разработчик должен отдавать в тестирование только тот код, который он сам проверил, чтобы исключить множество циклов доработки по возврату. Именно поэтому юнит-тесты занимают существенную часть пирамиды тестирования.

Юнит-тесты также можно проводить автоматически, встроив в CI/CD-конвейер. В CI-фазе важно, чтобы сборка проходила максимально быстро, поэтому там чаще всего запускают облегченные типы тестов, такие как юнит-тесты.

А что же такое компонентное тестирование? Оно находится уровнем выше модульного, соответственно для него справедлив один из принципов пирамиды: более высокий уровень тестирования не проверяет логику более низкого уровня, то есть компонентный тест не проверяет минимальную единицу кода. Компонентные тесты существуют на уровне целого компонента приложения и тестируют логику этого компонента в изоляции от других. Один компонент обычно имеет несколько зависимостей и состоит из нескольких сущностей, поэтому для проведения компонентных тестов также используются моки и заглушки.

Если рассматривать бекенд-часть на микросервисной архитектуре, то компонентом можно назвать один из микросервисов приложения. При тестировании отдельного сервиса для имитации внешних компонентов можно использовать моки, а для имитации базы данных – in-memory базы данных, что, однако, может несколько усложнить тест. В компонентных тестах сервис запускается локально, после чего можно обращаться к его эндпоинту.

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

Поскольку юнит-тесты являются слишком низкоуровневыми и атомарными, их результаты могут не всегда отражать реальное поведение приложения на практике. Компонентные тесты обеспечивают более целостное представление о приложении, но их разработка несколько сложнее юнит-тестов, поэтому они находятся уровнем выше. Точно также как юнит-тесты, компонентные тесты пишутся и запускаются самим разработчиками приложения.

Интеграционное тестирование

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

К примеру, на бекенде тест интеграции со сторонним сервисом через REST API может выглядеть следующим образом:

  1. запуск приложения;

  2. запуск инстанса стороннего сервиса;

  3. запуск функции в коде, которая считывает данные из API стороннего сервиса;

  4. проверка, что приложение правильно обрабатывает ответ.

Тест интеграции с базой данных может выглядеть следующим образом:

  1. запуск базы данных;

  2. подключение приложения к базе данных;

  3. запуск функции в коде, которая записывает данные в базу данных;

  4. проверка, что ожидаемые данные записаны в базу путем их чтения из базы данных.

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

  • вызовы REST API своих или сторонних сервисов;

  • чтение и запись данных в базе данных;

  • чтение из очереди и публикация сообщений в нее;

  • чтение из файловой системы и запись в нее;

  • чтение из объектного хранилища и запись в него.

При проведении интеграционных тестов можно либо локально запускать внешние зависимости, либо интегрироваться по сети с выделенным тестовым инстансом стороннего сервиса. Интеграция с сервисом по сети — это типичное свойство широкого интеграционного теста, но такие тесты обычно труднее писать, и они медленнее работают.

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

Контрактное тестирование

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

Интерфейс (или контракт) всегда должен быть четко прописан, так как зачастую бывает, что сервисы потребителей и поставщиков распределены между разными командами.

Результатом прогона контрактных тестов является констатация того, что поставщик API уверен в исправной работе потребителя.

Тестирование API

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

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

API тест для проверки функциональности выполняется путем отправки запроса к эндпоинту и сравнения ответа с ожидаемым результатом. Функциональные тесты на API считаются критически важными для автоматизации – они должны быть главным приоритетом у тестировщика-автоматизатора в команде.

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

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

Тестирование безопасности API включает в себя проверку аутентификации и авторизации, тестирование на наличие известных уязвимостей и защиту от атак путем внедрения или утечек данных.

Для проведения нагрузочного тестирования и тестирования безопасности существуют отдельные роли в тестировании – нагрузочный тестировщик и тестировщик безопасности, которые не всегда входят непосредственно в команду разработки приложения, поэтому эти виды тестов не включаются в пирамиду тестирования.

E2E тестирование

E2E (end-to-end) тестирование фокусируется на проверке поведения приложения при полном прохождении определенного пользовательского сценария и проводится тестировщиками. Данный вид тестирования затрагивает все подсистемы, компоненты и их интеграции, которые участвуют в цепочке бизнес-процессов приложения, и может гарантировать, что приложение работает должным образом при реальных жизненных сценариях. Обычно такое тестирование проводится после завершения интеграционного тестирования отдельных компонентов и тестирования API.

В E2E тестах не используются моки или заглушки, так как на этом уровне тестирования важно убедиться, что системная интеграция работает так, как ожидается.

Поскольку Е2Е тесты затрагивают всю цепочку действий пользователя и занимают довольно много времени, их количество минимально. E2E тесты не нацелены на абсолютное покрытие и не пытаются глубоко тестировать функциональность, на этом уровне пирамиды тестируются только критически важные бизнес-сценарии.

Проводить E2E тестирование можно через пользовательский интерфейс — это самое полное тестирование, какое только можно провести. Но если у приложения нет графического интерфейса, или в проекте нет необходимости проводить такие тесты через UI, то они проводятся только для API.

Тестирование пользовательского интерфейса

Тестирование пользовательского интерфейса находится на самом высоком уровне пирамиды и фокусируется на проверке корректности работы и удобства использования графического интерфейса приложения. Объектами тестирования на этом уровне выступают:

  • внешний вид и функциональность компонентов интерфейса;

  • отображение подсказок и сообщений об ошибках для пользователя;

  • навигация;

  • отзывчивость.

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

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

Заключение

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

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

Теги:
Хабы:
Всего голосов 6: ↑6 и ↓0+7
Комментарии1

Публикации

Работа

Ближайшие события