У вас наверняка было такое, когда вы и ваши друзья очень хотели посмотреть какой-нибудь фильм, а после жалели о том, что потратили на него время. Или, может быть, вы помните тот момент, когда ваша команда думала, что нашла «киллер фичу» и обнаруживала ее «подводные камни» только после выпуска продукта.
Хорошие идеи часто терпят неудачу на практике, и в мире тестирования хорошим примером этого может служить стратегия тестирования, построенная на автоматизации end-to-end тестов.
Тестировщики могут инвестировать свое время на написание многих типов автоматических тестов, включая модульные тесты, интеграционные тесты и end-2-end тесты, но эта стратегия в основном направлена на end-2-end тесты, которые проверяют продукт или услугу в целом. Как правило, эти тесты имитируют реальные пользовательские сценарии.
Источник
Хотя полагаться в первую очередь на end-2-end тесты — плохая идея, но теоретически можно придумать несколько доводов в пользу этого утверждения.
Итак, номер один в списке Google из десяти вещей, которые, как мы знаем, являются правдой: «Интересы пользователей превыше всего». Таким образом, использование end-2-end тестов, которые фокусируются на реальных пользовательских сценариях, выглядит отличной идеей. Кроме того, эта стратегия в целом привлекательна для многих участников процесса.
Итак, если эта стратегия тестирования выглядит так хорошо в теории, то что же с ней не так на практике? Чтобы продемонстрировать это, я ниже приведу выдуманный сценарий, но который основан на реальных ситуациях, знакомых как мне, так и другим тестировщикам.
Допустим команда создает сервис для редактирования документов в режиме онлайн (например, Google Docs). Давайте предположим, что у команды уже есть какая-то фантастическая инфраструктура для тестирования. Каждую ночь:
Крайний срок приближается быстро. Чтобы поддерживать высокую планку качества продукции, допустим, мы решаем, что требуется по крайней мере 90% успешных end-2-end тестов, чтобы мы считали что версия готова. Допустим, крайний срок наступает через один день.
![](https://habrastorage.org/r/w1560/webt/va/gp/wg/vagpwgs-6_wapdngvpzwlp8iooq.png)
Несмотря на многочисленные проблемы, тесты в конечном итоге выявили реальные ошибки.
Что прошло хорошо
Ошибки, влияющие на пользователя, были выявлены и исправлены до того, как они к нему попали.
Что пошло не так
Итак, теперь, когда мы знаем, что пошло не так в end-2-end стратегии, нам нужно изменить наш подход к тестированию, чтобы избежать многих из вышеперечисленных проблем. Но каков правильный подход?
Как правило, работа тестировщика заканчивается, когда тест провален. Ошибка регистрируется, и затем задача разработчика — исправить ошибку. Однако чтобы определить, где end-2-end стратегия не срабатывает, нам нужно выйти за рамки этого мышления и подойти к проблеме используя наши базовые принципы. Если мы «сосредоточимся на пользователе (а все остальное приложится)», мы должны спросить себя: приносит ли проваленный тест пользу пользователю?
Вот ответ: «Проваленный тест напрямую не приносит пользы пользователю».
Хотя это утверждение, на первый взгляд, кажется шокирующим, оно верно. Если продукт работает, он работает, независимо от того, говорит ли тест, что он работает или нет. Если продукт сломан, он сломан, независимо от того, говорит ли тест, что он сломан или нет. Итак, если проваленные тесты не приносят пользы пользователю, то что же приносит ему пользу?
Исправление ошибок напрямую приносит пользу пользователю.
Пользователь будет счастлив только тогда, когда это непредсказуемое поведение (ошибка) исчезнет. Очевидно, чтобы исправить ошибку, вы должны знать, что она существует. Чтобы узнать, что ошибка существует, в идеале у вас должен быть тест, который ее обнаруживает (потому что если тест не выявит ошибку, то ее найдет пользователь). Но во всем этом процессе, от провала теста до исправления ошибки, добавленная стоимость появляется на самом последнем шаге.
![](https://habrastorage.org/r/w1560/webt/en/4i/4y/en4i4yg7lsynu0xfm4_ccrs1pwm.png)
Таким образом, чтобы оценить любую стратегию тестирования, вы не можете просто оценить, как она находит ошибки. Вы также должны оценить, как это позволяет разработчикам исправлять (и даже предотвращать) их.
Тесты создают цикл обратной связи, который информирует разработчика о том, работает продукт или нет. Идеальный цикл обратной связи имеет несколько свойств.
Так как же нам создать этот идеальный цикл обратной связи? Думая о малом, а не о большем.
Модульное тестирование
Модульные тесты берут небольшой фрагмент продукта и тестируют его изолированно от всего остального. Они почти создают тот самый идеальный цикл обратной связи:
Написание эффективных модульных тестов требует навыков в таких областях, как управление зависимостями, написание заглушек/ mock-ов и герметичное тестирование. Я не буду описывать эти навыки здесь, но для начала типичный пример, предлагаемый новому Googler -у (или как их называют в Google — Noogler-у), — это то, как Google создает и тестирует секундомер.
Модульные тесты против end-2-end тестов
При end-2-end тестах вам нужно подождать: сначала создания всего продукта, затем его развертывания и, наконец, выполнения всех end-2-end тестов. Когда тесты все же заработали, вероятнее всего, они периодически будут сбоить. И даже если тест обнаружит ошибку, она может быть в любом месте продукта.
Хотя сквозные тесты лучше справляются с моделированием реальных пользовательских сценариев, это преимущество быстро перевешивается всеми недостатками сквозного цикла обратной связи:
![](https://habrastorage.org/r/w780q1/webt/q1/px/ex/q1pxexctftgcpo6oqftyavp3cn8.jpeg)
Интеграционные тесты
У модульных тестов есть один существенный недостаток: даже если модули работают хорошо по отдельности, вы не знаете, хорошо ли они работают вместе. Но даже тогда вам не обязательно проводить end-2-end тесты. Для этого вы можете использовать интеграционный тест. Интеграционный тест берет небольшую группу модулей, часто два, и тестирует их поведение как единого целого.
Если два блока не интегрируются должным образом, зачем писать сквозной тест, когда вы можете написать гораздо меньший, более сфокусированный интеграционный тест, который обнаруживает ту же ошибку? Конечно, вы должны понимать весь контекст при тестировании, но для того, чтобы проверить работу двух модулей вместе вам всего лишь нужно совсем чуть-чуть расширить перспективу.
Даже при проведении и модульных, и интеграционных тестов вам, скорее всего, потребуется небольшое количество end-2-end тестов для проверки системы в целом. Чтобы найти правильный баланс между всеми тремя типами тестов, лучше всего использовать визуальную пирамиду тестирования. Вот упрощенная версия пирамиды тестирования из вступительной речи конференции Google Test Automation 2014 года.
![](https://habrastorage.org/r/w1560/getpro/habr/post_images/542/f80/6c6/542f806c69fc676845d6b71f36084375.png)
Основная часть ваших тестов — это модульные тесты в нижней части пирамиды. По мере того как вы продвигаетесь вверх по пирамиде, ваши тесты становятся более всеобъемлющими, но в то же время количество тестов (ширина вашей пирамиды) уменьшается.
По-хорошему, Google предлагает разделение 70/20/10: 70% модульных тестов, 20% интеграционных тестов и 10% end-2-end тестов. Точное соотношение будет отличаться для каждой команды, но в целом она должна сохранять форму пирамиды. Старайтесь избегать следующих «форм»:
Точно так же, как обычная пирамида имеет тенденцию быть самой стабильной структурой в реальной жизни, пирамида тестирования также имеет тенденцию быть самой стабильной стратегией тестирования.
Если вы любите и умеете писать модульные тесты, то вам к нам! В компании ЛАНИТ открыта вакансия разработчика Java в DevOps команду, где вы найдете себе единомышленников.
Хорошие идеи часто терпят неудачу на практике, и в мире тестирования хорошим примером этого может служить стратегия тестирования, построенная на автоматизации end-to-end тестов.
Тестировщики могут инвестировать свое время на написание многих типов автоматических тестов, включая модульные тесты, интеграционные тесты и end-2-end тесты, но эта стратегия в основном направлена на end-2-end тесты, которые проверяют продукт или услугу в целом. Как правило, эти тесты имитируют реальные пользовательские сценарии.
![](https://habrastorage.org/webt/gs/2w/_z/gs2w_zh-jl0ki-mla34_nut9dqk.jpeg)
End-2-end тесты в теории
Хотя полагаться в первую очередь на end-2-end тесты — плохая идея, но теоретически можно придумать несколько доводов в пользу этого утверждения.
Итак, номер один в списке Google из десяти вещей, которые, как мы знаем, являются правдой: «Интересы пользователей превыше всего». Таким образом, использование end-2-end тестов, которые фокусируются на реальных пользовательских сценариях, выглядит отличной идеей. Кроме того, эта стратегия в целом привлекательна для многих участников процесса.
- Разработчикам эта стратегия нравится, потому что можно перенести бОльшую часть тестирования, если вообще не всю, на других.
- Руководителям и лицам, принимающим решения, она нравится, потому что тесты, имитирующие реальные пользовательские сценарии, могут помочь им легко определить, как неудачный тест повлияет на пользователя.
- Тестировщикам такая стратегия нравится, потому что они беспокоятся как бы не пропустить ошибки влияющие на пользователей и как бы не не написать тест, который не проверяет реальное поведение; написание тестов отталкиваясь от сценариев работы пользователя часто позволяет избежать обеих проблем и дает тестировщику чувство выполненного долга.
End-2-end тесты на практике
Итак, если эта стратегия тестирования выглядит так хорошо в теории, то что же с ней не так на практике? Чтобы продемонстрировать это, я ниже приведу выдуманный сценарий, но который основан на реальных ситуациях, знакомых как мне, так и другим тестировщикам.
Допустим команда создает сервис для редактирования документов в режиме онлайн (например, Google Docs). Давайте предположим, что у команды уже есть какая-то фантастическая инфраструктура для тестирования. Каждую ночь:
- выполняется сборка последней версии сервиса,
- затем эта версия развертывается в среде тестирования команды,
- затем в этой среде тестирования прогоняются все сквозные тесты,
- команда получает по электронной почте отчет с кратким изложением результатов тестирования.
Крайний срок приближается быстро. Чтобы поддерживать высокую планку качества продукции, допустим, мы решаем, что требуется по крайней мере 90% успешных end-2-end тестов, чтобы мы считали что версия готова. Допустим, крайний срок наступает через один день.
![](https://habrastorage.org/webt/va/gp/wg/vagpwgs-6_wapdngvpzwlp8iooq.png)
Несмотря на многочисленные проблемы, тесты в конечном итоге выявили реальные ошибки.
Что прошло хорошо
Ошибки, влияющие на пользователя, были выявлены и исправлены до того, как они к нему попали.
Что пошло не так
- Команда завершила свой этап программирования на неделю позже (и много работала сверхурочно).
- Поиск основной причины неудачного end-2-end теста является трудоемким и может занять много времени.
- Неудачи параллельной команды и сбои в оборудовании сдвинули результаты тестов на несколько дней.
- Многие мелкие ошибки были спрятаны за большими ошибками.
- Результаты end-2-end тестов временами были ненадежными.
- Разработчикам пришлось подождать до следующего дня, чтобы узнать, сработало ли исправление или нет.
Итак, теперь, когда мы знаем, что пошло не так в end-2-end стратегии, нам нужно изменить наш подход к тестированию, чтобы избежать многих из вышеперечисленных проблем. Но каков правильный подход?
Истинная ценность тестов
Как правило, работа тестировщика заканчивается, когда тест провален. Ошибка регистрируется, и затем задача разработчика — исправить ошибку. Однако чтобы определить, где end-2-end стратегия не срабатывает, нам нужно выйти за рамки этого мышления и подойти к проблеме используя наши базовые принципы. Если мы «сосредоточимся на пользователе (а все остальное приложится)», мы должны спросить себя: приносит ли проваленный тест пользу пользователю?
Вот ответ: «Проваленный тест напрямую не приносит пользы пользователю».
Хотя это утверждение, на первый взгляд, кажется шокирующим, оно верно. Если продукт работает, он работает, независимо от того, говорит ли тест, что он работает или нет. Если продукт сломан, он сломан, независимо от того, говорит ли тест, что он сломан или нет. Итак, если проваленные тесты не приносят пользы пользователю, то что же приносит ему пользу?
Исправление ошибок напрямую приносит пользу пользователю.
Пользователь будет счастлив только тогда, когда это непредсказуемое поведение (ошибка) исчезнет. Очевидно, чтобы исправить ошибку, вы должны знать, что она существует. Чтобы узнать, что ошибка существует, в идеале у вас должен быть тест, который ее обнаруживает (потому что если тест не выявит ошибку, то ее найдет пользователь). Но во всем этом процессе, от провала теста до исправления ошибки, добавленная стоимость появляется на самом последнем шаге.
![](https://habrastorage.org/webt/en/4i/4y/en4i4yg7lsynu0xfm4_ccrs1pwm.png)
Таким образом, чтобы оценить любую стратегию тестирования, вы не можете просто оценить, как она находит ошибки. Вы также должны оценить, как это позволяет разработчикам исправлять (и даже предотвращать) их.
Построение правильной обратной связи
Тесты создают цикл обратной связи, который информирует разработчика о том, работает продукт или нет. Идеальный цикл обратной связи имеет несколько свойств.
- Он должен быть быстрым. Ни один разработчик не хочет ждать часами или днями, чтобы узнать, работает ли его изменение. Иногда изменение не работает (никто не совершенен), и цикл обратной связи должен выполняться несколько раз. Более быстрый цикл обратной связи приводит к более быстрым исправлениям. Если цикл достаточно быстр, разработчики могут даже запустить тесты перед проверкой изменений.
- Он должен быть надежным. Ни один разработчик не хочет тратить часы на отладку теста, только для того, чтобы выяснить, что сам тест был ошибочным. Ненадежные тесты снижают доверие разработчика к ним, и в результате такие тесты часто игнорируются, даже когда они обнаруживают реальные проблемы с продуктом.
- Он должен позволять быстро находить ошибки. Чтобы исправить ошибку, разработчикам необходимо найти конкретное строки кода, вызывающие ошибку. Когда продукт содержит миллионы строк кодов, а ошибка может быть где угодно, это все равно что пытаться найти иголку в стоге сена.
Думайте о малом, а не о большем
Так как же нам создать этот идеальный цикл обратной связи? Думая о малом, а не о большем.
Модульное тестирование
Модульные тесты берут небольшой фрагмент продукта и тестируют его изолированно от всего остального. Они почти создают тот самый идеальный цикл обратной связи:
- Модульные тесты быстрые. Нам нужно написать небольшой блок кода и мы уже можем тестировать его. Модульные тесты, как правило, довольно маленькие. На самом деле, одна десятая секунды — слишком долго для модульных тестов.
- Модульные тесты надежны. Простые системы и небольшие модули кода, как правило, гораздо более устойчивые. Кроме того, лучшие практики модульного тестирования — в частности, практики, связанные с герметичными тестами — полностью устраняют такие проблемы.
- Модульные тесты позволяют быстро найти ошибки. Даже если продукт содержит миллионы строк кода, если модульный тест не пройден, то вы, скорее всего, взглянув на тестируемый модуль сразу поймете в чем ошибка.
Написание эффективных модульных тестов требует навыков в таких областях, как управление зависимостями, написание заглушек/ mock-ов и герметичное тестирование. Я не буду описывать эти навыки здесь, но для начала типичный пример, предлагаемый новому Googler -у (или как их называют в Google — Noogler-у), — это то, как Google создает и тестирует секундомер.
Модульные тесты против end-2-end тестов
При end-2-end тестах вам нужно подождать: сначала создания всего продукта, затем его развертывания и, наконец, выполнения всех end-2-end тестов. Когда тесты все же заработали, вероятнее всего, они периодически будут сбоить. И даже если тест обнаружит ошибку, она может быть в любом месте продукта.
Хотя сквозные тесты лучше справляются с моделированием реальных пользовательских сценариев, это преимущество быстро перевешивается всеми недостатками сквозного цикла обратной связи:
![](https://habrastorage.org/webt/q1/px/ex/q1pxexctftgcpo6oqftyavp3cn8.jpeg)
Интеграционные тесты
У модульных тестов есть один существенный недостаток: даже если модули работают хорошо по отдельности, вы не знаете, хорошо ли они работают вместе. Но даже тогда вам не обязательно проводить end-2-end тесты. Для этого вы можете использовать интеграционный тест. Интеграционный тест берет небольшую группу модулей, часто два, и тестирует их поведение как единого целого.
Если два блока не интегрируются должным образом, зачем писать сквозной тест, когда вы можете написать гораздо меньший, более сфокусированный интеграционный тест, который обнаруживает ту же ошибку? Конечно, вы должны понимать весь контекст при тестировании, но для того, чтобы проверить работу двух модулей вместе вам всего лишь нужно совсем чуть-чуть расширить перспективу.
Пирамида тестов
Даже при проведении и модульных, и интеграционных тестов вам, скорее всего, потребуется небольшое количество end-2-end тестов для проверки системы в целом. Чтобы найти правильный баланс между всеми тремя типами тестов, лучше всего использовать визуальную пирамиду тестирования. Вот упрощенная версия пирамиды тестирования из вступительной речи конференции Google Test Automation 2014 года.
![](https://habrastorage.org/getpro/habr/post_images/542/f80/6c6/542f806c69fc676845d6b71f36084375.png)
Основная часть ваших тестов — это модульные тесты в нижней части пирамиды. По мере того как вы продвигаетесь вверх по пирамиде, ваши тесты становятся более всеобъемлющими, но в то же время количество тестов (ширина вашей пирамиды) уменьшается.
По-хорошему, Google предлагает разделение 70/20/10: 70% модульных тестов, 20% интеграционных тестов и 10% end-2-end тестов. Точное соотношение будет отличаться для каждой команды, но в целом она должна сохранять форму пирамиды. Старайтесь избегать следующих «форм»:
- Перевернутая пирамида / рожок мороженого. Команда опирается в основном на сквозные тесты, используя несколько интеграционных тестов и совсем немного модульных тестов.
- Песочные часы. Команда начинает с большого количества модульных тестов, а затем использует сквозные тесты там, где должны использоваться интеграционные тесты. Песочные часы имеют много модульных тестов в нижней части и много сквозных тестов в верхней части, но мало интеграционных тестов в середине.
Точно так же, как обычная пирамида имеет тенденцию быть самой стабильной структурой в реальной жизни, пирамида тестирования также имеет тенденцию быть самой стабильной стратегией тестирования.
Вакансии
Если вы любите и умеете писать модульные тесты, то вам к нам! В компании ЛАНИТ открыта вакансия разработчика Java в DevOps команду, где вы найдете себе единомышленников.