Дымовое тестирование при ежедневной сборке программного продукта. В чем разница между дымовым и санитарным тестированием

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

    В 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
  • Добавить метки
    • 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

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

    - Дымовое тестирование (Smoke Testing)

    - Регрессионное тестирование (Regression Testing)

    - Тестирование сборки (Build Verification Test)

    - Санитарное тестирование или проверка согласованности/исправности (Sanity Testing)

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

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

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

    Сам по себе термин «Регрессионное тестирование», в зависимости от контекста использования может иметь разный смысл. Сэм Канер, к примеру, описал 3 основных типа регрессионного тестирования:

    - Регрессия багов (Bug regression) – попытка доказать, что исправленная ошибка на самом деле не исправлена.

    - Регрессия старых багов (Old bugs regression) – попытка доказать, что недавнее изменение кода или данных сломало исправление старых ошибок, т.е. старые баги стали снова воспроизводиться.


    - Регрессия побочного эффекта (Side effect regression) – попытка доказать, что недавнее изменение кода или данных сломало другие части разрабатываемого приложения.

    Санитарное тестирование или проверка согласованности/исправности (Sanity Testing) – это узконаправленное тестирование, достаточное для доказательства того, что конкретная функция работает согласно заявленным в спецификации требованиям. Является подмножеством регрессионного тестирования. Используется для определения работоспособности определенной части приложения после изменений произведенных в ней или окружающей среде. Обычно выполняется вручную.

    Отличие санитарного тестирования от дымового. В некоторых источниках ошибочно полагают, что санитарное и дымовое тестирование – это одно и тоже. Мы же полагаем, что эти виды тестирования имеют «вектора движения», направления в разные стороны. В отличии от дымового (Smoke testing), санитарное тестирование (Sanity testing) направлено вглубь проверяемой функции, в то время как дымовое направлено вширь, для покрытия тестами как можно большего функционала в кратчайшие сроки.

    Тестирование сборки (Build Verification Test) – это тестирование, направленное на определение соответствия, выпущенной версии, критериям качества для начала тестирования. По своим целям является аналогом Дымового Тестирования, направленного на приемку новой версии в дальнейшее тестирование или эксплуатацию. Вглубь оно может проникать дальше, в зависимости от требований к качеству выпущенной версии.

    Тестирование Установки (Installation Testing) – направленно на проверку успешной инсталляции и настройки, а также обновления или удаления программного обеспечения. В настоящий момент наиболее распространена установка ПО при помощи инсталляторов (специальных программ, которые сами по себе так же требуют надлежащего тестирования). В реальных условиях инсталляторов может не быть. В этом случае придется самостоятельно выполнять установку программного обеспечения, используя документацию в виде инструкций или readme файлов, шаг за шагом описывающих все необходимые действия и проверки. В распределенных системах, где приложение разворачивается на уже работающем окружении, простого набора инструкций может быть мало. Для этого, зачастую, пишется план установки (Deployment Plan), включающий не только шаги по инсталляции приложения, но и шаги отката (roll–back) к предыдущей версии, в случае неудачи. Сам по себе план установки также должен пройти процедуру тестирования для избежания проблем при выдаче в реальную эксплуатацию. Особенно это актуально, если установка выполняется на системы, где каждая минута простоя – это потеря репутации и большого количества средств, например: банки, финансовые компании или даже баннерные сети. Поэтому тестирование установки можно назвать одной из важнейших задач по обеспечению качества программного обеспечения.

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

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

    В 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 для всего этого потребовалось бы в разы больше времени и ресурсов. Добавить метки

    What is Smoke Testing?

    Smoke testing is defined as a type of software testing that determines whether the deployed build is stable or not. This serves as confirmation whether the QA team can proceed with further testing. Smoke tests are a minimal set of tests run on each build. Here is the cycle where smoke testing is involved

    Smoke testing is a process where the software build is deployed to QA environment and is verified to ensure the stability of the application. It is also called as "Build verification Testing" or “Confidence Testing.”

    In simple terms, we are verifying whether the important features are working and there are no showstoppers in the build that is under testing.

    It is a mini and rapid regression test of major functionality. It is a simple test that shows the product is ready for testing. This helps determine if the build is flawed as to make any further testing a waste of time and resources.

    The smoke tests qualify the build for further formal testing. The main aim of smoke testing is to detect early major issues. Smoke tests are designed to demonstrate system stability and conformance to requirements.

    A build includes all data files, libraries, reusable modules, engineered components that are required to implement one or more product functions.

    In this tutorial, you will learn-

    When do we do smoke testing

    Smoke Testing is done whenever the new functionalities of software are developed and integrated with existing build that is deployed in QA/staging environment. It ensures that all critical functionalities are working correctly or not.

    In this testing method, the development team deploys the build in QA. The subsets of test cases are taken, and then testers run test cases on the build. The QA team test the application against the critical functionalities. These series of test cases are designed to expose errors that are in build. If these tests are passed, QA team continues with Functional Testing .

    Any failure indicates a need to handle the system back to the development team. Whenever there is a change in the build, we perform Smoke Testing to ensure the stability.

    Example : -New registration button is added in the login window and build is deployed with the new code. We perform smoke testing on a new build.

    Who will do Smoke Testing

    After releasing the build to QA environment, Smoke Testing is performed by QA engineers/QA lead. Whenever there is a new build, QA team determines the major functionality in the application to perform smoke testing. QA team checks for showstoppers in the application that is under testing.

    Testing done in a development environment on the code to ensure the correctness of the application before releasing build to QA, this is known as Sanity testing. It is usually narrow and deep testing. It is a process which verifies that the application under development meets its basic functional requirements.

    Sanity testing determines the completion of the development phase and makes a decision whether to pass or not to pass software product for further testing phase.

    Why do we do smoke testing?

    Smoke testing plays an important role in software development as it ensures the correctness of the system in initial stages. By this, we can save test effort. As a result, smoke tests bring the system to a good state. Once we complete smoke testing then only we start functional testing.

    • All the show stoppers in the build will get identified by performing smoke testing.
    • Smoke testing is done after the build is released to QA. With the help of smoke testing, most of the defects are identified at initial stages of software development.
    • With smoke testing, we simplify the detection and correction of major defects.
    • By smoke testing, QA team can find defects to the application functionality that may have surfaced by the new code.
    • Smoke testing finds the major severity defects.

    Example 1: Logging window: Able to move to next window with valid username and password on clicking submit button.

    Example 2: Userunable to sign out from the webpage.

    How to do Smoke Testing ?

    Smoke Testing is usually done manually though there is a possibility of accomplishing the same through automation. It may vary from organization to organization.

    Manual Smoke testing

    In general, smoke testing is done manually. It approaches varies from one organization to other. Smoke testing is carried to ensure the navigation of critical paths is as expected and doesn"t hamper the functionality. Once the build is released to QA, high priority functionality test cases are to be taken and are tested to find the critical defects in the system. If the test passes, we continue the functional testing. If the test fails, the build is rejected and sent back to the development team for correction. QA again starts smoke testing with a new build version. Smoke testing is performed on new build and will get integrated with old builds to maintain the correctness of the system. Before performing smoke testing, QA team should check for correct build versions.