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

Перевод разбавлен размышлениями и дополнениями автора из своего опыта

О чём это всё

Будучи инженером по тестированию, вы, вероятно, слышали о таких видах тестирования как «дымовое» (smoke), «санитарное тестирование» (sanity), «ре-тест» и регрессионное тестирование. Вполне возможно, многие из этих видов используются вами на ежедневной основе.

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

Для новичков в тестировании (и даже опытных тестировщиков) разделение этих понятий может быть затруднительно. И в самом деле, как отличить где начинается санити-тестирование и заканчивается smoke? Насколько сильно нам надо ограничить проверку части функциональности системы или её компонентов, чтобы назвать это «дымовым» тестированием? Является ли ввод логина/пароля в пользовательскую форму входа на сайт дымовым тестом, или сам факт её появления на странице сайта уже является пройденным тестом?

Строго говоря, вы всё равно сможете проводить тестирование, даже при том что не сможете точно сказать, в чём же разница. Можно даже не задумываться о разграничении, каким именно видом тестирования вы сейчас заняты. Но всё же, чтобы расти над собой в профессиональном смысле, нужно знать что вы делаете, зачем, и насколько правильно вы это делаете.

Ликбез

Ниже приведены краткие определения видов тестирования, которые мы сегодня сравниваем:
  • Дымовые тесты : выполняются каждый раз, когда мы получаем новый билд (версию), проекта (системы) на тестирование, при этом считая её относительно нестабильной. Нам нужно убедиться что критически важные функции AUT (Application Under Test) работают согласно ожиданиям. Идея данного вида тестирования заключается в том, чтобы выявить серьёзные проблемы как можно раньше, и отклонить этот билд (вернуть на доработку) на раннем этапе тестирования, чтобы не углубляться в долгие и сложные тесты, не затрачивая тем самым время на заведомо бракованное ПО.
  • Санитарное тестирование : используется каждый раз, когда мы получаем относительно стабильный билд ПО, чтобы определить работоспособность в деталях. Иными словами, здесь проходит валидация того, что важные части функциональности системы работают согласно требованиям на низком уровне.
Оба эти вида тестирования нацелены на то, чтобы избежать потерь времени и усилий, чтобы быстрее определить недостатки ПО и их критичность, а так же то, заслуживает ли оно перехода в фазу более углублённого и тщательного тестирования или же нет.
  • Ре-тест : проводится в случае, если фича/функциональность уже имела дефекты, и эти дефекты были недавно исправлены
  • Регрессионные тесты : собственно то, что занимает львиную долю времени и для чего существует автоматизация тестирования. Проводится регрессионное тестирование AUT тогда, когда нужно убедиться что новые (добавленные) функции приложения / исправленные дефекты не оказали влияния на текущую, уже существующую функциональность, работавшую (и протестированную) ранее.
Для лучшего понимания ниже представлена сравнительная таблица этих понятий и области применения:
Дымовые (Smoke) Санити (Sanity) Регрессионные (Regression) Ре-тест (Re-test)
Исполняются с целью проверить что критически важные функциональные части AUT работают как положено Нацелено на установление факта того, что определённые части AUT всё так же работают как положено после минорных изменений или исправлений багов Подтверждают, что свежие изменения в коде или приложении в целом не оказали негативного влияния на уже существующую функциональность/набор функций Перепроверяет и подтверждает факт того, что ранее заваленные тест-кейсы проходят после того, как дефекты исправлены
Цель - проверить «стабильность» системы в целом, чтобы дать зелёный свет проведению более тщательного тестирования Целью является проверить общее состояние системы в деталях, чтобы приступить к более тщательному тестированию Цель - убедиться что свежие изменения в коде не оказали побочных эффектов на устоявшуюся работающую функциональность Ре-тест проверяет что дефект исправлен
Перепроверка дефектов не является целью Smoke Перепроверка дефектов не является целью Sanity Перепроверка дефектов не является целью Regression Факт того что дефект исправлен подтверждает Re-Test
Дымовое тестирование выполняется перед регрессионным Санитарное тестирование выполняется перед регрессионным и после smoke-тестов Проводится на основании требований проекта и доступности ресурсов (закрывается автотестами), «регресс» может проводиться в параллели с ре-тестами - Ре-тест выполняется перед sanity-тестированием
- Так же, приоритет ре-теста выше регрессионных проверок, поэтому должно выполняться перед ними
Может выполняться автоматизированно или вручную Чаще выполняется вручную Лучший повод для автоматизации данного вида тестирования, т.к. ручное может быть крайне затратным по ресурсам или времени Не поддаётся автоматизации
Является подмножеством регрессионного тестирования Подмножество приёмочного тестирования Выполняется при любой модификации или изменениях в уже существующем проекте Ре-тест проводится на исправленной сборке с использованием тех же данных, на том же окружении, но с различным набором входных данных
Тест-кейсы часть регрессионных тест-кейсов, но покрывающие крайне критичную функциональность Санитарное может выполняться без тест-кейсов, но знание тестируемой системы обязательно Тест-кейсы регрессионного тестирования могут быть получены из функциональных требований или спецификаций, пользовательских мануалов, и проводятся вне зависимости от того, что исправили разработчики Используется тот же самый тест-кейс, который выявил дефект

Ну а по существу?

Приведу пример разграничения понятий на моём текущем проекте.

Пример: у нас есть веб-сервис с пользовательским интерфейсом и RESTful API. Будучи тестировщиками, мы знаем:

  • Что у него есть 10 точек входа, для простоты, в нашем случае расположенных на одном IP
  • Мы знаем все они принимают GET-запрос на вход, возвращая какие-либо данные в формате json.
Тогда можно сделать ряд утверждений о том, какие типы тестов нужно использовать в какой момент времени:
  • Выполнив один простой GET-запрос к одной из этих точек входа, и получив ответ в формате json, мы уже убеждаемся что дымное тестирование пройдено.
    Если же одна из этих точек входа так же возвращает данные из БД, тогда как первая - нет, нужно дополнительно выполнить ещё один запрос, чтобы убедиться что приложение
    верно обрабатывает запросы к базе. И на этом «дымный» тест закончен.

    То есть мы выполнили запрос - от сервиса пришёл ответ, и он не «задымился», то есть не вернул ошибку 4хх или 5хх, и что-то невнятное, вместо json. На этом можно сказать что «дымный» тест пройден. Для проверки того, что работает так же и UI достаточно просто один раз открыть страницу в браузере.

  • Санитарное тестирование в данном случае будет состоять из выполнения запроса ко всем 10 точкам входа в api, сверкой полученного json с ожидаемым, а так же наличием требуемых данных в нём.
  • Регрессионные тесты будут состоять из smoke + sanity + UI выполняемые вместе в одной куче. Цель: проверить что добавление 11-ой точки входа не поломало, к примеру, восстановление пароля.
  • Ре-тест в данном примере это точечная проверка что, к примеру, сломавшаяся точка входа в api в следующем билде отрабатывает как задумывалось.
При этом, если это api принимает так же post-запросы, то очевидно что в другой набор тестов sanity нужно включить именно эти запросы. По аналогии с UI мы будем проверять все страницы приложения.

Подведём итог

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

UPD :
Часто «тестирование согласованности» или «тестированием на вменяемость», называют термином «санитарное тестирование». Думаю что это пошло из-за фонетических свойств английского слова sanity, схожего по звучанию с чем-то «санитарным». Гугл транслейт вносит ясность . В интернете встречаются оба варианта. Относительно данной статьи прошу считать «санитарное» тестирование как «тестирование на согласованность».

Спасибо за наводку

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

Дымовое тестирование:

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

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

Санитарное тестирование:

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

Пример для лучшего понимания разницы между дымовым и санитарным тестированием:

Есть проект, для которого запланирован первоначальный релиз. Команда разработчиков выпускает билд на тестирование, команда тестировщиков начинает работу. Самое первое тестирование — это тестирование на пригодность. Нужно выяснить, можно работать с этой версией или нет. Это и есть дымовое тестирование. Если команда дает добро на дальнейшую работу с билдом, он отправляется на более глубокие стадии тестирования. Представим, что у билда есть три модуля: “Логин”, “Админ” и “Сотрудник”. Команда тестировщиков проверяет работоспособность исключительно основных функций каждого из модулей, не углубляясь в проверку частностей. Это будет санитарное тестирование.

Еще несколько различий между дымовым и санитарным тестированием:

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

Кирилл Флягин, геймдизайнер, QA Lead

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

  • Smoke test на Jargon File (англ.)

Wikimedia Foundation . 2010 .

Смотреть что такое "Smoke test" в других словарях:

    smoke test - noun A method of testing for leaks in drain pipes or chimneys by introducing dense smoke, often by using a smoke bomb Main Entry: smoke … Useful english dictionary

    smoke test - Test made to determine completeness of combustion … Dictionary of automotive terms

    smoke test - 1. noun a) A test for leaks involving blowing smoke into a tube or pipe. b) A preliminary test on a newly constructed piece of electronic equipment, consisting simply of the application of electrical power, to make sure that no egregious wiring… … Wiktionary

    Smoke testing - is a term used in plumbing, woodwind repair, electronics, computer software development, and the entertainment industry. It refers to the first test made after repairs or first assembly to provide some assurance that the system under test will… … Wikipedia

    Smoke testing - bzw. Rauchtest ist ein Begriff aus dem Englischen, gebräuchlich im handwerklichen Bereich (z. B. in der Klempnerei, Elektronik oder beim Bau von Holzblasinstrumenten) wie auch in der Softwareentwicklung. Es bezeichnet den ersten… … Deutsch Wikipedia

    Smoke - is the collection of airborne solid and liquid particulates and gases [ SFPE Handbook of Fire Protection Engineering] emitted when a material undergoes… … Wikipedia

    Test suite - In software development, a test suite, less commonly known as a validation suite , is a collection of test cases that are intended to be used to test a software program to show that it has some specified set of behaviours. A test suite often… … Wikipedia

    Smoke bomb - A smoke bomb is a firework designed to produce smoke upon ignition. While there are smoke generating devices that are dropped from airplanes, the term smoke bomb is used to describe the three types of devices:# A smoke ball is a hollow, cherry… … Wikipedia

Если Вы хотите создать простую компьютерную программу, которая состоит из одного файла, Вам просто необходимо собрать и связать весь написанный вами код в этот файл. На самом обычном проекте, которым занимается команда разработчиков, существуют сотни, даже тысячи файлов. Это «способствует» тому, что процесс создания выполнимой программы становится всё более сложным и трудоёмким: вы должны «собирать» программу из различных компонентов.

Практика применяемая, к примеру, в Microsoft и некоторых других компаниях, занимающихся разработкой ПО, заключается в ежедневной сборке (билдовании) программы, которая дополняется дымовым тестированием. Ежедневно, после того, как каждый файл собран (сбилдован, построен), связан (слинкован), и объединен в выполнимую программу, сама программа подвергается достаточно простому набору тестов, цель которых заключается в том, чтобы увидеть, «дымит» ли программа во время работы. Эти тесты и называются дымовыми (от англ. smoke - дым). Чаще всего этот процесс достаточно хорошо автоматизирован (или должен таким быть).

ПРЕИМУЩЕСТВА. Этот простой процесс обеспечивает несколько существенных преимуществ.

Минимизация риска при интеграции

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

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

Снижения риска низкого качества программного продукта

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

Помощь в диагностике ошибок

Если в один прекрасный день продукт не собрался (собрался с ошибками), то с помощью ежедневной сборки и прогона набора дымовых тестов гораздо проще найти причину проблемы. Работающий продукт вчера и не работающий сегодня - это явный намек на то, что что-то не ладное произошло между двумя сборками.

Улучшение морального духа

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

Использование ежедневного билдования и дымовых тестов

Вот несколько подробностей этого принципа.

Ежедневная сборка приложения

Фундаментальной частью ежедневной сборки является сборка той части, что была сделана последней. Джим Маккарти (Jim McCarthy) в журнале Dynamics of Software Development (Microsoft Press, 1995) назвал ежедневное билдование проекта его сердцебиением. Если сердцебиения нет - проекта нет, он мертв. Менее образно ежедневное билдование описали Майкл Касамано (Michael Cusumano) и Ричард Селби (Richard W. Selby), назвав его синхронизирующим импульсом проекта (Microsoft Secrets, The Free Press, 1995). Каждый разработчик пишет код по своему и он, код, может выходить за общепринятые на проекте рамки - это нормально, но при каждом воздействии синхронизирующего импульса код возвращается к стандарту. Настаивая на ведении разработки с использованием импульса синхронизации постоянно, Вы препятствуете выходу проекта из синхронизации полностью.

В некоторых компаниях принято собирать проект не каждый день, а раз в неделю. Эта система ошибочна, т.к. в случае «поломки» в проекте на текущей неделе, может пройти ещё пара недель до следующей удачной сборки. В таком случае компания теряет все преимущества системы ежедневной сборки проекта.

Проверка на неудачную сборку

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

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

Хорошей сборкой является та, при которой как минимум:

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

Ежедневные дымовые тесты

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

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

Дымовое тестирование должно развиваться на уровне с проектом. В начале, дымовые тесты будут проверять что-то простое, например, может ли проект выдавать сообщение «Hello, World!». С развитием системы, дымовые тесты становятся более глубокими. Время, которое тратится на первые дымовые тесты, исчисляется несколькими секундами, однако с ростом системы растет и количество необходимого для дымового тестирования времени. В конце проекта дымовое тестирование может длится на протяжении часов.

Определение группы сборки

На большинстве проектов, есть определенный сотрудник, ответственный за проверку ежедневной сборки системы и выполнение дымовых тестов. Эта работа является частью обязанностей данного сотрудника, но на больших проектах таких сотрудников может быть больше и такая работа является основной их обязанностью. Например, в группе сборки проекта Windows NT 3.0 было четыре человека (Pascal Zachary, Showstopper! , The Free Press, 1994).

Добавляйте ревизию в сборку только если это имеет смысл

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

Введите систему штрафов за срыв выпуска очередной сборки (выпуск не рабочей сборки).

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

Незначительные штрафы подчеркивают высокую степень необходимости следить за качеством сборки системы. На некоторых проектах разработчикам, по вине которых сборка «падает», выдают леденцы за выпуск неработающей сборки. На двери кабинета такого разработчика висит соответствующая вывеска до тех пор, пока он не починит сборку (при условии, что у разработчиков отдельные кабинеты:)). На других проектах виновные разработчики должны носить искусственные козлиные рога или вносить определенную сумму в «фонд морального духа» (примеры взяты из истории реальных компаний).

Но на некоторых проектах вводятся более серьезные штрафные санкции. Например, разработчики компании Microsoft, состоящие в проектах с высоким приоритетом (Windows NT, Windows 95, Excel), носили пейджеры и, в случае обнаружения проверки, они должны были прибыть на работу. Даже если поломка или ошибка были обнаружены в 3 утра.

Собирайте систему и «дымите» ее даже под давлением

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

Кто выигрывает от этого процесса? Некоторые разработчики протестуют против ежедневных сборок, обосновывая свои протесты непрактичностью этого занятия и его большими временными затратами. Но все сложные системы последнего времени подвергались ежедневным сборкам и прогонке дымовых тестов. К моменту своего выпуска, Microsoft Windows NT 3.0 содержала в 40 000 файлах 5,6 миллионов строк. Полная сборка занимала 19 часов и выполнялась на нескольких компьютерах. Несмотря на это, разработчики умудрялись ежедневно собирать систему. Будучи профессиональной командой, группа разработчиков NT, своим успехом во многом обязана ежедневной сборке. Те разработчики, которые работают на менее сложных проектах и, поэтому, не пользуются преимуществами процесса ежедневной сборки, должны задуматься над тем, чтоб придумать себе какие-то разумные объяснения.

  • Тестирование веб-сервисов ,
  • Тестирование мобильных приложений
  • Привет, Хабр! Как-то раз на нашем внутреннем семинаре мой руководитель – глава отдела тестирования – начал свою речь со слов «тестирование не нужно». В зале все притихли, некоторые даже пытались упасть со стульев. Он продолжил свою мысль: без тестирования вполне возможно создать сложный и дорогостоящий проект. И, скорее всего, он будет работать. Но представьте, насколько увереннее вы будете себя ощущать, зная, что продукт работает как надо.

    В Badoo релизы происходят довольно часто. Например, серверная часть наравне с desktop web релизится дважды в день. Так что мы не понаслышке знаем, что сложное и медленное тестирование – камень преткновения разработки. Быстрое же тестирование – это счастье. Итак, сегодня я расскажу о том, как в компании Badoo устроено smoke-тестирование.

    Что такое smoke-тестирование

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

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

    Давайте рассмотрим простой пример. Предпродакшн нашего приложения находится по адресу bryak.com (любые совпадения с реальными сайтами случайны). Мы подготовили и залили туда новый релиз для тестирования. Что стоит проверить в первую очередь? Я бы начал с проверки того, что приложение всё ещё открывается. Если web-сервер нам отвечает «200», значит, всё хорошо и можно приступать к проверке функционала.

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

    Наш первый smoke-тест

    В Badoo серверная часть написана по большей части на PHP. Unit-тесты по понятным причинам пишутся на нём же. Итого у нас уже есть PHPUnit. Чтобы не плодить технологии без необходимости, мы решили писать smoke-тесты тоже на PHP. Помимо PHPUnit, нам потребуется клиентская библиотека работы с URL (libcurl) и PHP extension для работы с ней – cURL.

    По сути, тесты просто делают нужные нам запросы на сервер и проверяют ответы. Всё завязано на методе getCurlResponse() и нескольких типах ассертов.

    Сам метод выглядит примерно так:

    Public function getCurlResponse($url, array $params = [ ‘cookies’ => , ‘post_data’ => , ‘headers’ => , ‘user_agent’ => , ‘proxy’ => , ], $follow_location = true, $expected_response = ‘200 OK’) { $ch = curl_init(); curl_setopt($ch, CURLOPT_URL, $url); curl_setopt($ch, CURLOPT_HEADER, 1); curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1); if (isset($params[‘cookies’]) && $params[‘cookies’]) { $cookie_line = $this->prepareCookiesDataByArray($params[‘cookies’]); curl_setopt($ch, CURLOPT_COOKIE, $cookie_line); } if (isset($params[‘headers’]) && $params[‘headers’]) { curl_setopt($ch, CURLOPT_HTTPHEADER, $params[‘headers’]); } if (isset($params[‘post_data’]) && $params[‘post_data’]) { $post_line = $this->preparePostDataByArray($params[‘post_data’]); curl_setopt($ch, CURLOPT_POST, 1); curl_setopt($ch, CURLOPT_POSTFIELDS, $post_line); } if ($follow_location) { curl_setopt($ch, CURLOPT_FOLLOWLOCATION, 1); } if (isset($params[‘proxy’]) && $params[‘proxy’]) { curl_setopt($ch, CURLOPT_PROXY, $params[‘proxy’]); } if (isset($params[‘user_agent’]) && $params[‘user_agent’]) { $user_agent = $params[‘user_agent’]; } else { $user_agent = USER_AGENT_DEFAULT; } curl_setopt($ch, CURLOPT_USERAGENT, $user_agent); curl_setopt($ch, CURLOPT_AUTOREFERER, 1); $response = curl_exec($ch); $this->logActionToDB($url, $user_agent, $params); if ($follow_location) { $this->assertTrue((bool)$response, "Empty response was received. Curl error: " . curl_error($ch) . ", errno: " . curl_errno($ch)); $this->assertServerResponseCode($response, $expected_response); } curl_close($ch); return $response; }
    Сам метод умеет по заданному URL возвращать ответ сервера. На вход принимает параметры, такие как cookies, headers, user agent и прочие данные, необходимые для формирования запроса. Когда ответ от сервера получен, метод проверяет, что код ответа совпадает с ожидаемым. Если это не так, тест падает с ошибкой, сообщающей об этом. Это сделано для того, чтобы было проще определить причину падения. Если тест упадёт на каком-нибудь ассерте, сообщив нам, что на странице нет какого-то элемента, ошибка будет менее информативной, чем сообщение о том, что код ответа, например, «404» вместо ожидаемого «200».

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

    Самый простой тест выглядит примерно так:

    Public function testStartPage() { $url = ‘bryak.com’; $response = $this->getCurlResponse($url); $this->assertHTMLPresent("
    Такой тест проходит менее чем за секунду. За это время мы проверили, что стартовая страница отвечает «200», и на ней есть элемент body. С тем же успехом мы можем проверить любое количество элементов на странице, продолжительность теста существенно не изменится.

    Плюсы таких тестов:

    • скорость – тест можно запускать так часто, как это необходимо. Например, на каждое изменение кода;
    • не требуют специального софта и железа для работы;
    • их несложно писать и поддерживать;
    • они стабильные.
    По поводу последнего пункта. Я имею в виду – не менее стабильные, чем сам проект.

    Авторизация

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

    Самый просто вариант – авторизационная cookie. Если добавить её к запросу, то сервер нас «узнает». Такую cookie можно захардкодить в тесте, если её время жизни довольно большое, а можно получать автоматически, отправляя запросы на страницу авторизации. Давайте подробнее рассмотрим второй вариант.

    Нас интересует форма, куда надо ввести логин и пароль пользователя.

    Открываем эту страницу в любом браузере и открываем инспектор. Вводим данные пользователя и сабмитим форму.

    В инспекторе появился запрос, который нам надо имитировать в тесте. Можно посмотреть, какие данные, помимо очевидных (логин и пароль), отсылаются на сервер. Для каждого проекта по-разному: это может быть remote token, данные каких-либо cookies, полученных ранее, user agent и так далее. Каждый из этих параметров придётся предварительно получить в тесте, прежде чем сформировать запрос на авторизацию.

    В инструментах разработчика любого браузера можно скопировать запрос, выбрав пункт copy as cURL. В таком виде команду можно вставить в консоль и рассматривать там. Там же её можно опробовать, поменяв или добавив параметры.

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

    Поскольку авторизация – довольно долгий процесс, авторизационную cookie я предлагаю получать только один раз для каждого пользователя и сохранять где-то. У нас, например, такие cookies хранятся в массиве. Ключом является логин пользователя, а значением – информация о них. Если для следующего пользователя ключа ещё нет, авторизуемся. Если есть – делаем интересующий нас запрос сразу.

    Public function testAuthPage() { $url = ‘bryak.com’; $cookies = $this->getAuthCookies(‘[email protected]’, ‘12345’); $response = $this->getCurlResponse($url, [‘cookies’ => $cookies]); $this->assertHTMLPresent("", $response, "Error: test cannot find body element on the page."); }
    Как мы видим, добавился метод, который получает авторизационную cookie и просто добавляет её в дальнейший запрос. Сам метод реализуется довольно просто:

    Public function getAuthCookies($email, $password) { // check if cookie already has been got If (array_key_exist($email, self::$known_cookies)) { return self::$known_cookies[$email]; } $url = self::DOMAIN_STAGING . ‘/auth_page_adds’; $post_data = [‘email’ => $email, ‘password’ => $password]; $response = $this->getCurlResponse($url, [‘post_data’ => $post_data]); $cookies = $this->parseCookiesFromResponse($response); // save cookie for further use self::$known_cookies[$email] = $cookies; return $cookies; }
    Метод сначала проверяет, есть ли для данного e-mail (в вашем случаем это может быть логин или что-то ещё) уже полученная ранее авторизационная cookie. Если есть, он её возвращает. Если нет, он делает запрос на авторизационную страницу (например, bryak.com/auth_page_adds) с необходимыми параметрами: e-mail и пароль пользователя. В ответ на этот запрос сервер присылает заголовки, среди которых есть интересующие нас cookies. Выглядит это примерно так:

    HTTP/1.1 200 OK Server: nginx Content-Type: text/html; charset=utf-8 Transfer-Encoding: chunked Connection: keep-alive Set-Cookie: name=value; expires=Wed, 30-Nov-2016 10:06:24 GMT; Max-Age=-86400; path=/; domain=bryak.com
    Из этих заголовков нам при помощи несложного регулярного выражения надо получить название cookie и её значение (в нашем примере это name=value). У нас метод, который парсит ответ, выглядит так:

    $this->assertTrue((bool)preg_match_all("/Set-Cookie: (([^=]+)=([^;]+);.*)\n/", $response, $mch1), "Cannot get "cookies" from server response. Response: " . $response);
    После того, как cookies получены, мы можем смело добавлять их в любой запрос, чтобы сделать его авторизованным.

    Разбор падающих тестов

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

    Прежде всего я бы хотел посоветовать максимально атомизировать тесты. Не стоит в одном тесте проверять 50 различных кейсов. Чем тест проще, тем с ним проще будет в дальнейшем.

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

    Например, тест у нас упал на том, что не может найти на странице кусочек HTML:

    Link
    Мы заходим на наш коллектор и открываем соответствующую страницу:

    С этой страницей можно работать так же, как с любой другой HTML-страничкой в браузере. Можно при помощи CSS-локатора попытаться разыскать пропавший элемент и, если его действительно нет, решить, что либо он изменился, либо потерялся. Возможно, мы нашли баг! Если элемент на месте, возможно, мы где-то ошиблись в тесте – надо внимательно посмотреть в эту сторону.

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

    Помимо помощи в разборе ошибок, логи, описанные выше, помогают нам формировать список авторизованных и неавторизованных страниц, которые мы протестировали. Глядя на него, легко искать и устранять пробелы.

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

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

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

    Итоги

    На данный момент у нас *открываю Тимсити* ого, уже 605 тестов. Все тесты, если их запускать не параллельно, проходят чуть меньше, чем за четыре минуты.

    За это время мы убеждаемся, что:

    • наш проект открывается на всех языках (которых у нас более 40 на продакшене);
    • для основных стран отображаются корректные формы оплаты с соответствующим набором способов оплаты;
    • корректно работают основные запросы к API;
    • корректно работает лендинг для редиректов (в том числе и на мобильный сайт при соответствующем юзер-агенте);
    • все внутренние проекты отображаются правильно.
    Тестам на Selenium WebDriver для всего этого потребовалось бы в разы больше времени и ресурсов.
  • smoke
  • Добавить метки