|
|
@@ -1,32 +1,28 @@ |
|
|
# Автоматизированное тестирование |
|
|
|
|
|
Если ты пишешь код, то наверняка его тестируешь. Если речь о какой-то функции, то ты можешь вызывать ее с разными аргументами, и смотреть, что она вернет. Если ты сверстал сайт, то ты открываешь его в браузере, жмешь ссылки и кнопки, проверяешь что все сделано верно. Это называется ручное тестирование — человек проверяет работу программы. Нельзя ли эту задачу переложить на плечи роботов? Обычно можно, и это называется автоматизированное тестирование. |
|
|
Обычно после написания кода его проверяют. Если речь о какой-то функции, то можно написать простой скрипт, который будет вызывать ее с разными аргументами, и смотреть, что она вернет. Если вы сделали сайт или приложение, то вы открываете его, жмете ссылки и кнопки, проверяете что все отображается верно. Это называется *ручное тестирование* или *QA* (Quality Assurance — контроль качества) — человек проверяет работу программы. Если мы попробуем автоматизировать этот процесс, и написать программу, которая проверяет правильность другой программы, то это называется *автоматизированное тестирование*. |
|
|
|
|
|
Тестирование позволяет сделать твой код надежнее, а твою жизнь проще. Ведь согласись, лучше когда ты сам обнаруживаешь и исправляешь ошибку до релиза, чем когда рассерженный заказчик звонит на выходных и требует срочно исправить неработающий функционал. |
|
|
Главный плюс автоматических тестов — то, что они выполняются намного быстрее, чем ручное тестирование, и вам не надо тратить на это свое время (или время тестировщика). Это позволяет запускать их хоть после каждого изменения в коде. |
|
|
|
|
|
Тестирование особенно полезно при разработке больших приложений в большой команде, когда ты можешь нечаянно сломать какую-то функцию, которую делал другой человек, и о которой ты не знал. Или когда надо доработать написанный ранее сложный проект. |
|
|
|
|
|
В больших компаниях может быть отдельная группа людей, которые занимаются только тестированием. Обычно их называют QA (Quality Assurance). |
|
|
Также, тесты позволяют «защитить» написанный код. Если кто-то в команде (или вы сами) нечаянно «сломал» ваш код, тесты это обнаружат и укажут, что именно перестало работать. Поэтому править код становится комфортнее и спокойнее — не надо бояться, что в ходе правки вы сломали какой-то функционал и не заметили. Тестирование особенно полезно при разработке сложных приложений в большой команде. |
|
|
|
|
|
Ниже будет краткий обзор разных подходов к тестированию, а в конце практические задания на написание тестов. |
|
|
|
|
|
## Что можно тестировать |
|
|
|
|
|
Тестировать программу можно на разных уровнях: код (юнит-тесты и интеграционное тестирование), API (если оно есть) и GUI. Разные виды тестов лучше подходят в разных ситуациях. |
|
|
Тестировать программу можно на разных уровнях: код (юнит-тесты и интеграционное тестирование), API (если оно есть) и GUI (интерфейс пользователя). Разные виды тестов лучше подходят в разных ситуациях. |
|
|
|
|
|
### Тестирование кода |
|
|
### Виды тестов |
|
|
|
|
|
Код тестируется на разных уровнях: |
|
|
|
|
|
**Юнит-тесты** ([вики](https://ru.wikipedia.org/wiki/%D0%9C%D0%BE%D0%B4%D1%83%D0%BB%D1%8C%D0%BD%D0%BE%D0%B5_%D1%82%D0%B5%D1%81%D1%82%D0%B8%D1%80%D0%BE%D0%B2%D0%B0%D0%BD%D0%B8%D0%B5)) — это тестирование одного модуля кода (обычно это одна функция или один класс в случае ООП-кода) в изолированном окружении. Это значит, что если код использует какие-то сторонние классы, то вместо них подсовываются классы-заглушки (*моки* и *стабы*), код не должен работать с сетью (и внешними серверами), файлами, базой данных (иначе мы тестируем не саму функцию или класс, а еще и диск, базу, ит.д.). |
|
|
|
|
|
Стабы — это классы-заглушки, которые вместо выполнения действия возвращают какие-то данные (то есть по сути функция состоит из одного `return`). Например, стаб класса работы с базой данных может вместо реального обращения к базе данных возвращать, что запрос успешно выполнен. А при попытке прочитать что-то из нее возвращает заранее подготовленный массив с данными. |
|
|
**Юнит-тесты** ([вики](https://ru.wikipedia.org/wiki/%D0%9C%D0%BE%D0%B4%D1%83%D0%BB%D1%8C%D0%BD%D0%BE%D0%B5_%D1%82%D0%B5%D1%81%D1%82%D0%B8%D1%80%D0%BE%D0%B2%D0%B0%D0%BD%D0%B8%D0%B5)) — это тестирование одного элемента кода (например, отдельная функция или класс в случае ООП-кода) в изоляции от остальной части программы. Это значит, что если код обращается к каким-то другим классам, то вместо них подсовываются классы-заглушки (*моки* и *стабы*). Если код обращается к файлам, базе данных, по сети, то это все тоже заменяется на заглушки, возвращающие заранее подготовленные данные. Это делается потому, что в юнит-тестировании мы тестируем именно одну функцию, а не правильность работы базы данных, жесткого диска или удаленного сервера. |
|
|
|
|
|
Моки — это классы-заглушки, которые используются чтобы проверить, что определенная функция была вызвана (по моему, они не очень часто нужны). |
|
|
*Стабы* — это классы-заглушки, которые вместо выполнения действия возвращают какие-то данные. Например, стаб класса работы с базой данных может вместо реального обращения к базе данных возвращать, что запрос успешно выполнен. А при попытке прочитать что-то из нее возвращает готовый массив с данными. |
|
|
|
|
|
Обычно юнит-тест передает функции разные входные данные и проверяет, что она вернет ожидаемый результат. Например, если у нас есть функция проверки правильности номера телефона, мы даем ей заранее подготовленные номера, и проверяем что она определит их правильно. Если у нас есть функция решения квадратного уравнения, мы проверяем, что она возвращает правильные корни (для этого мы заранее делаем список уравнений с ответами). |
|
|
*Моки* — это классы-заглушки, которые используются чтобы проверить, что определенная функция была вызвана с определенными аргументами. |
|
|
|
|
|
Юнит-тесты хорошо тестируют такой код, который содержит какую-то логику. Если в коде мало логики, а в основном содержатся обращения к другим классам, то юнит-тесты написать может быть сложно (так как надо сделать замену для других классов и не очень понятно, что именно проверять?). |
|
|
Обычно юнит-тест передает функции разные входные данные и проверяет, что она вернет ожидаемый результат. Юнит-тесты хорошо тестируют такой код, который содержит какую-то логику. Если в коде мало логики, а в основном содержатся обращения к другим классам, то юнит-тесты написать может быть сложно, так как нужно большое число заглушек. |
|
|
|
|
|
**Интеграционные тесты** тестируют какой-то компонент системы, обычно состоящий из многих модулей (классов или функций). Например, для блога мы можем тестировать, что при вызове функции сохранения поста в базе данных появляется этот пост, у него верно проставляются теги, число комментариев равно нулю. А при добавлении комментария оно увеличивается на один. Заодно, можно протестировать, например что пост с незаполненным названием не сохраняется. |
|
|
|
|
|
@@ -36,13 +32,13 @@ |
|
|
|
|
|
Если проводить аналогии, например с тестированием авиадвигателя, то юнит-тесты - это тестирование отдельных деталей, клапанов, заслонок, а интеграционное тестирование — это запуск собранного двигателя на стенде. |
|
|
|
|
|
Тестировать можно не любой код. Если например в твоем коде жестко прописаны параметры соединения с базой данных или пути к папкам без возможности их поменять, ты вряд ли сможешь использовать для тестов временную БД. То же самое, если классы в твоем коде сильно связаны и ты не используешь dependency injection, если используются глобальные переменные или везде статические методы. В общем, пиши качественно. |
|
|
Тестировать можно не любой код. Если например в твоем коде жестко прописаны параметры соединения с базой данных или пути к папкам без возможности их поменять, вы вряд ли сможете использовать для тестов временную БД. То же самое, если классы в твоем коде сильно связаны и вы не используете dependency injection, если используются глобальные переменные или везде статические методы. В общем, пиши качественно. |
|
|
|
|
|
### Тестирование API |
|
|
|
|
|
API ([wiki](http://ru.wikipedia.org/wiki/%D0%98%D0%BD%D1%82%D0%B5%D1%80%D1%84%D0%B5%D0%B9%D1%81_%D0%BF%D1%80%D0%BE%D0%B3%D1%80%D0%B0%D0%BC%D0%BC%D0%B8%D1%80%D0%BE%D0%B2%D0%B0%D0%BD%D0%B8%D1%8F_%D0%BF%D1%80%D0%B8%D0%BB%D0%BE%D0%B6%D0%B5%D0%BD%D0%B8%D0%B9)) — это набор функций, которые можно вызывать, чтобы получить какие-то данные. Ну, например, у яндекс-карт есть [АПИ геокодера](https://tech.yandex.ru/maps/doc/geocoder/desc/concepts/About-docpage/). Отправив к нему запрос с географическим адресом, ты можешь получить координаты точки (и наоборот), а [у Центробанка есть API](http://www.cbr.ru/scripts/Root.asp?PrtId=DWS), которое возвращает официальный курс валют в заданный день. |
|
|
API ([wiki](http://ru.wikipedia.org/wiki/%D0%98%D0%BD%D1%82%D0%B5%D1%80%D1%84%D0%B5%D0%B9%D1%81_%D0%BF%D1%80%D0%BE%D0%B3%D1%80%D0%B0%D0%BC%D0%BC%D0%B8%D1%80%D0%BE%D0%B2%D0%B0%D0%BD%D0%B8%D1%8F_%D0%BF%D1%80%D0%B8%D0%BB%D0%BE%D0%B6%D0%B5%D0%BD%D0%B8%D0%B9)) — это набор функций, которые можно вызывать, чтобы получить какие-то данные. Ну, например, у яндекс-карт есть [АПИ геокодера](https://tech.yandex.ru/maps/doc/geocoder/desc/concepts/About-docpage/). Отправив к нему запрос с географическим адресом, вы можете получить координаты точки (и наоборот), а [у Центробанка есть API](http://www.cbr.ru/scripts/Root.asp?PrtId=DWS), которое возвращает официальный курс валют в заданный день. |
|
|
|
|
|
Если у твоего приложения есть API, то можно тестировать его, посылая заранее подготовленные запросы и сравнивая пришедший ответ с ожидаемым. |
|
|
Если у твоего приложения есть API, то можно тестировать его, посылая заранее подготовленные запросы и сравнивая пришедший ответ с ожидаемым. Тестировать приложение через API удобно и несложно. |
|
|
|
|
|
### Тестирование GUI |
|
|
|
|
|
@@ -62,59 +58,98 @@ GUI тесты еще называют End-to-End (E2E) или приемочн |
|
|
убедиться, что на странице выводится текст «Вы зарегистрированы на сайте» |
|
|
``` |
|
|
|
|
|
Для тестирования веб-приложения (сайта) необходимо имитировать работу браузера. Для этого есть разные подходы. Есть простые инструменты, которые лишь умеют отправлять HTTP-запросы к серверу и анализировать полученный HTML-код, и более продвинутые, которые либо используют настоящий браузерный движок (вроде PhantomJS) в «headless» режиме (то есть без вывода окошка со страницей на экран), а самые продвинутые предоставляют драйверы, с помощью которых можно контролировать реальный браузер (Selenium). |
|
|
Для тестирования веб-приложения (сайта) необходимо имитировать работу браузера. Для этого есть разные подходы. Есть простые инструменты, которые лите умеют отправлять HTTP-запросы к серверу и анализировать полученный HTML-код, и более продвинутые, которые либо используют настоящий браузерный движок (вроде PhantomJS) в «headless» режиме (то есть без вывода окошка со страницей на экран), а самые продвинутые предоставляют драйверы, с помощью которых можно контролировать реальный браузер (Selenium). |
|
|
|
|
|
Простые HTML-браузеры хороши тем, что работают гораздо быстрее, но они не интерпретируют CSS- и JS-код и не могут проверить например видимость кнопки или работу скриптов. PhantomJS это умеет. Selenium позволяет получить наиболее полноценную имитацию действий пользователя, в том числе например тестирование в определенной версии браузера или использование флеш-плагина, но сложен в настройке: требуется где-то запускать эти браузеры, надо поднимать сеть виртуальных машин с нужными операционными системами и тесты на нем медленнее работают. |
|
|
|
|
|
PhantomJS и Selenium умеют делать скриншот страницы, который можно будет посмотреть при неудачном выполнении теста. |
|
|
|
|
|
## Тестируем без фанатизма |
|
|
## Как пишутся тесты |
|
|
|
|
|
При тестировании не стоит впадать в крайности. Например, нельзя говорить, что «100% кода должно быть покрыто юнит-тестами». Тесты должны прежде всего повышать качество кода, и требуют времени на их написание, отладку, поддержку. Если эти затраты больше, чем приносимая от них выгода, возможно они не требуются. |
|
|
Составление тестов начинается со сбора списка требований к тестируемому коду. Затем для каждого требования пишется тестовый сценарий, который проверяет, что оно выполняется. Сценарии бывают *позитивными* — когда мы передаем корректные данные и ждем успешный результат, и *негативными* — когда мы передаем неправильные данные и ждем сообщение об ошибке. |
|
|
|
|
|
Например, если ты делаешь небольшой сайт, который потом не надо поддерживать, то наверно проще просмотреть его глазами, и сдать, чем тратить время на тесты. |
|
|
Вот пример сбора требований. Допустим, что у нас есть функция `truncate`, которая обрезает строку, если она длиннее N символов. Каким требованиям она должна соответствовать? |
|
|
|
|
|
В некоторых случаях высокая надежность не требуется. Если местный городской сайт не работает некоторое время, ничего страшного не случится. |
|
|
- если передать ей строку `hello` из 5 символов и `N` = 10, функция должна вернуть строку без изменений |
|
|
- если передать ей строку `hello world` из 11 символов и `N` = 5, то функция должна обрезать строку до `hello…` |
|
|
|
|
|
С другой стороны, если большая команда работает над сложным приложением, тесты необходимы, иначе большую часть времени вы будете тратить на исправление сломанного нечаянно функционала. К сожалению, не везде внедрено автоматизированное тестирование, где-то программа проверяется людьми. Люди устают, могут быть ленивы или невнимательны, в то время как робот готов хоть круглосуточно выполнять одну и ту же последовательность действий. |
|
|
Вот более сложный пример. Допустим, у нас есть система бронирования номеров в отеле, и мы хотим написать интеграционные тесты для класса `ReservationService`, который отвечает за создание броней. Тут список требований будет другой: |
|
|
|
|
|
Также, есть подход, когда сначала пишутся тесты (которыми задаются требования к коду), а только потом сам код. Это называется [TDD](http://ru.wikipedia.org/wiki/%D0%A0%D0%B0%D0%B7%D1%80%D0%B0%D0%B1%D0%BE%D1%82%D0%BA%D0%B0_%D1%87%D0%B5%D1%80%D0%B5%D0%B7_%D1%82%D0%B5%D1%81%D1%82%D0%B8%D1%80%D0%BE%D0%B2%D0%B0%D0%BD%D0%B8%D0%B5). Есть также его последователь [BDD](http://en.wikipedia.org/wiki/Behavior-driven_development), где сценарии пишутся на странном языке Gherkin и напоминают обычный текст. |
|
|
- если передать корректные дату заезда, дату выезда, количество человек и в наличии есть свободные номера, то должна создаться бронь |
|
|
- если дата выезда раньше или совпадает с датой заезда, должна вернуться ошибка |
|
|
- если количество человек меньше или равно нулю, должна вернуться ошибка |
|
|
- если свободных номеров на выбранные даты нет, должна вернуться ошибка |
|
|
|
|
|
## Что важно помнить |
|
|
На каждое требование мы пишем отдельный тест - это позволит при ошибке понять, что именно сломалось. Тесты обычно пишут в стиле Arrange, Act, Assert. Мы сначала подготавливаем и настраиваем нужные компоненты (Arrange), выполняем действие (Act) и проверяем результат (Assert). |
|
|
|
|
|
Тесты должны быть повторяемыми. Например, нельзя получать исходные данные генератором случайных чисел, так как в этом случае мы не сможем повторить тест. |
|
|
Тесты обычно пишут не с нуля, а с использованием фреймфорка. Для PHP есть 2 популярных фреймворка - это [PhpUnit](https://phpunit.de/) и [Codeception](https://codeception.com/). Вот пример PhpUnit-тестов для описанной выше функции `truncate`: |
|
|
|
|
|
Тесты должны выполняться в контролируемом окружении. |
|
|
```php |
|
|
class TruncateTest extends \PHPUnit\Framework\TestCase |
|
|
{ |
|
|
public function testShortStringRemainsAsIs() |
|
|
{ |
|
|
// Act: вызываем функцию |
|
|
$result = truncate("hello", 10); |
|
|
// Assert: проверяем, что возвращенный результат совпадает с ожидаемым |
|
|
$this->assertEquals("hello", $result); |
|
|
} |
|
|
|
|
|
public function testLongStringIsTruncated() |
|
|
{ |
|
|
$result = truncate("hello world", 5); |
|
|
$this->assertEquals("hello…", $result); |
|
|
} |
|
|
} |
|
|
``` |
|
|
|
|
|
Тест не должен использовать тот же алгоритм, что и проверяемый код (так как в этом случае в них может быть сделана одна и та же ошибка и результаты совпадут). |
|
|
Метод `assertEquals()` из PhpUnit проверяет, что фактический результат совпадает с ожидаемым, и выдает ошибку, если это не так. В PhpUnit много assert-функций на все случаи жизни. |
|
|
|
|
|
## Какими должны быть тесты |
|
|
|
|
|
- **маленькими** - идеальный тест укладывается в 5-15 строк и проверяет только одно требование. Он должен быть легко читаемым, чтобы с первого взгляда был очевиден сценарий, по которому происходит тестирование. |
|
|
- **повторяемым** - тест должен выдавать одинаковый результат при каждом запуске. Стоит избегать использования случайных величин, так как иначе может получиться «*нестабильный*» (flaky) тест, который то работает, то нет, и каждый раз надо тратить время, и искать причину. |
|
|
- тест не должен использовать тот же алгоритм, что и проверяемый код, так как можно сделать одинаковую ошибку и в коде и в тесте, и не заметить её. Например, если мы тестируем функцию решения уравнения, то проверять ее можно подстановкой решения обратно в уравнение. |
|
|
|
|
|
Тесты должны выполняться в контролируемом окружении. |
|
|
|
|
|
Надо тестировать и позитивные, и негативные сценарии. К примеру, при тестировании формы регистрации надо проверить не только как она работает при вводе правильных данных, но и как она работает с неправильными данными (должна выдавать сообщение об ошибке). |
|
|
|
|
|
При выполнении тестов надо отслеживать (автоматизированно) возникающие ошибки. Если у тебя при возникновении ошибки просто выводится сообщение (которое робот не читает) и программа продолжает выполняться, это довольно бесполезный тест. |
|
|
Тесты должно быть легко запустить, в идеале одной командой. Если для его запуска надо выполнить много действий, то людям будет лень это делать. В компаниях обычно настраивают CI сервер, который сам выкачивает обновления из репозитория, запускает тесты, и рассылает разработчикам сообщения при ошибках. |
|
|
|
|
|
Тесты должно быть легко запустить, в идеале одной командой. Если для его запуска надо выполнить много действий, то людям будет лень это делать. В компаниях обычно настраивают CI сервер, который сам выкачивает обновления их репозитория, запускает тесты, и рассылает разработчикам сообщения при ошибках. |
|
|
## Каким должен быть код |
|
|
|
|
|
## Еще способы тестирования и повышения надежности кода |
|
|
Не любой код удобно тестировать. Например, если функция не возвращает результат своей работы через `return`, а выводит его на экран через `echo`, то ее тестировать будет неудобно. Или, если класс содержит в себе обращения к какому-то API, то трудно будет заменить это в тестах на заглушку. Потому при написании кода стоит задумываться об удобстве тестирования. |
|
|
|
|
|
## Тестируем без фанатизма |
|
|
|
|
|
При тестировании не стоит впадать в крайности. Например, нельзя говорить, что «100% кода должно быть покрыто юнит-тестами». Тесты должны прежде всего повышать качество кода, и требуют времени на их написание, отладку, поддержку. Если эти затраты больше, чем приносимая от них выгода, возможно они не требуются. |
|
|
|
|
|
**Использование assertions и тайп-хинтов**. `assert()` ([мануал](http://php.net/manual/ru/function.assert.php)) — это функция, которая выдает ошибку если условие в скобках не выполняется. Например, если ты сделал функцию, и она принимает только числа от 0 до 5, логично в начале поставить `assert` для проверки этого: |
|
|
Например, если вы делаете небольшой сайт, который потом не надо поддерживать, то наверно проще просмотреть его глазами, и сдать, чем тратить время на тесты. А в некоторых случаях высокая надежность не требуется. Если местный городской сайт не работает некоторое время, ничего страшного не случится. |
|
|
|
|
|
С другой стороны, если большая команда работает над сложным приложением, тесты необходимы, иначе большую часть времени вы будете тратить на исправление сломанного нечаянно функционала. К сожалению, не везде внедрено автоматизированное тестирование, где-то программа проверяется людьми. Люди устают, могут быть ленивы или невнимательны, в то время как робот готов хоть круглосуточно выполнять одну и ту же последовательность действий. |
|
|
|
|
|
Также, есть подход, когда сначала пишутся тесты (которыми задаются требования к коду), а только потом сам код. Это называется [TDD](http://ru.wikipedia.org/wiki/%D0%A0%D0%B0%D0%B7%D1%80%D0%B0%D0%B1%D0%BE%D1%82%D0%BA%D0%B0_%D1%87%D0%B5%D1%80%D0%B5%D0%B7_%D1%82%D0%B5%D1%81%D1%82%D0%B8%D1%80%D0%BE%D0%B2%D0%B0%D0%BD%D0%B8%D0%B5). Есть также его последователь [BDD](http://en.wikipedia.org/wiki/Behavior-driven_development), где сценарии пишутся на странном языке Gherkin и напоминают обычный текст. |
|
|
|
|
|
## Дополнительные способы тестирования и повышения надежности кода |
|
|
|
|
|
**Использование assertions и тайп-хинтов**. `assert()` ([мануал](http://php.net/manual/ru/function.assert.php)) — это функция, которая выдает ошибку если условие в скобках не выполняется. Например, если вы написали функцию, и она принимает только числа от 0 до 5, логично в начале поставить `assert` для проверки этого: |
|
|
|
|
|
```php |
|
|
function doSomething($a) |
|
|
function doSomething(int $a) |
|
|
{ |
|
|
assert($a >= 0 && $a <= 5); |
|
|
... |
|
|
``` |
|
|
|
|
|
С одной стороны, ты сразу же обнаружишь ошибку если передаешь в нее что-то не то, с другой стороны, это документирует код и делает его более понятным. |
|
|
С одной стороны, вы сразу же обнаружите ошибку если передаете в нее что-то не то, с другой стороны, это документирует код и делает его более понятным. |
|
|
|
|
|
[Type hint](http://php.net/manual/ru/language.oop5.typehinting.php) — это конструкция, которая указывает что аргумент функции должен быть массивом или объектом определенного класса. При попытке передать в нее что-то другое произойдет фатальная ошибка. Используй тайп хинты везде, где можно. Пример: |
|
|
[Type hint](https://www.php.net/manual/ru/functions.arguments.php#functions.arguments.type-declaration) — это конструкция, которая указывает, какой тип должен иметь аргумент или результат функции (а в PHP ≥ 7.4 можно еще указывать тип для свойств класса). Если нарушить это требование, то произойдет ошибка. Например: |
|
|
|
|
|
```php |
|
|
function doSomething(SomeClass $a, array $b) { |
|
|
function doSomeWork(SomeClass $a, string $b): int |
|
|
``` |
|
|
|
|
|
**Тестирование через вызов контроллера** — это что-то вроде GUI тестирования, только без отправки HTTP-запросов (и имитации работы браузера), используя вызов контроллеров напрямую. Обычно это используется с приложениями на фреймворках вроде Yii2 или Symfony2. |
|
|
|
|
|
**Статический анализ кода**. Специальная программа проверяет исходники, не запуская код, с целью найти опечатки и неправильные куски кода. Такая программа хорошо ищет ошибки ситаксиса: `$x = ($x + 1;` (пропущена скобка), опечатки вроде `if ($x = 1)` (используется `=` вместо `==` в if), опечатки в именах переменных, функций и классов, обращение к несуществующей переменной. |
|
|
|
|
|
**[Fuzz testing](http://en.wikipedia.org/wiki/Fuzz_testing)** — это тестирование на основе случайно сгенерированных данных. Оно может применяться, например, для поиска уязвимостей или проверки работы кода при подаче на вход неожиданных значений. |
|
|
@@ -125,67 +160,51 @@ function doSomething(SomeClass $a, array $b) { |
|
|
|
|
|
Вот ссылка про нагрузочное тестирование в Яндексе: http://habrahabr.ru/company/yandex/blog/202020/ |
|
|
|
|
|
**Регрессионное тестирование** — это тестирование, что ранее обнаруженная ошибка больше не встречается. Если ты нашел какой-то баг, ты пишешь тест на него и больше он не останется незамеченным. |
|
|
**Регрессионное тестирование** — это тестирование, что ранее обнаруженная ошибка больше не встречается. Если вы нашел какой-то баг, вы пишете тест на него и больше он не останется незамеченным. |
|
|
|
|
|
**Тестирование на основе скриншотов** — статья от Яндекса http://habrahabr.ru/company/yandex/blog/200968/ |
|
|
|
|
|
## Инструменты |
|
|
|
|
|
Тесты гораздо удобнее писать на основе готовых библиотек и фреймворков, чем с нуля. Некоторые из них интегрируются с IDE и позволяют запускать тесты нажатием кнопки. Вот популярные инструменты для тестирования веб-приложений на PHP/JS. |
|
|
|
|
|
## Тестирование PHP кода |
|
|
|
|
|
### PhpUnit |
|
|
|
|
|
[Сайт](https://phpunit.de/) (англ.), [частичный перевод документации](http://phpunit-doc.verber.kh.ua/3.7/ru/index.html), в гугле много статей по нему. Несмотря на название, он годится не только для unit-тестов, но и для интеграционных, а так же браузерных через Selenium. Он также представляет функции для генерации моков и стабов из существующих классов. |
|
|
[Сайт](https://phpunit.de/) (англ.), [перевод документации](https://phpunit.readthedocs.io/ru/latest/), в гугле много статей по нему. Несмотря на название, он годится не только для unit-тестов, но и для интеграционных, а так же браузерных через Selenium. Он также представляет функции для генерации моков и стабов из существующих классов. |
|
|
|
|
|
Сам phpUnit распространяется в виде одного файла phpunit.phar, и ты запускаешь его командой вроде |
|
|
Сам phpUnit распространяется в виде одного файла phpunit.phar, и вы запускаете его командой вроде |
|
|
|
|
|
php phpunit.phar .... |
|
|
|
|
|
Чтобы увидеть список всех доступных опций, можно набрать |
|
|
|
|
|
php phpunit.phar --help |
|
|
|
|
|
(если ты не работал с командной строкой и плохо понимаешь, о чем речь, прочти [мой гайд по командной строке](https://gist.github.com/codedokode/10539568)). |
|
|
|
|
|
Тесты для phpunit хранятся в файлах (их может быть много, и при желании их можно раскладывать по папкам), каждый файл содержит 1 класс, унаследованный от встроенного в phpUnit класса `PHPUnit_Framework_TestCase`. А этот класс может содержать 1 или больше методов с конкретными тестовыми примерами. Давай напишем тест, проверяющий работу php-функции `count` (она возвращает число элементов в массиве, и тестом мы проверим что она делает это правильно). |
|
|
(если вы не работали с командной строкой и плохо понимаете, о чем речь, прочтите [мой урок по командной строке](https://github.com/codedokode/pasta/blob/master/soft/cli.md)). |
|
|
|
|
|
```php |
|
|
class FunctionCountTest extends \PHPUnit_Framework_TestCase |
|
|
{ |
|
|
public function testFunctionCount() |
|
|
{ |
|
|
// Протестируем работу стандартной функции count |
|
|
$array3 = array(1, 2, 3); |
|
|
$array0 = array(); |
|
|
$array1 = array(1); |
|
|
|
|
|
// count($array3) должно вернуть 3 |
|
|
$this->assertEquals(3, count($array3)); |
|
|
$this->assertEquals(0, count($array0)); |
|
|
$this->assertEquals(1, count($array1)); |
|
|
} |
|
|
} |
|
|
``` |
|
|
Тесты для phpunit хранятся в файлах (их может быть много, и при желании их можно раскладывать по папкам), каждый файл содержит 1 класс, унаследованный от встроенного в phpUnit класса `PHPUnit\Framework\TestCase`. А этот класс может содержать 1 или больше методов с конкретными тестовыми примерами. |
|
|
|
|
|
Каждый метод, имя которого начинается с `test`, будет выполнен. Также, ты можешь добавить методы `setUp` и `tearDown`, которые будут вызываться до и после каждого теста. |
|
|
Обычно название класса теста соответствует названию того класса или функции, которые он проверяет. Например, для тестирования класса `src/Hotel/RoomManager.php` логично создать тест `tests/Hotel/RoomManagerTest.php`. |
|
|
|
|
|
Встроенный в phpUnit метод `assertEquals` проверяет что второй аргумент равен первому, а если это не так, то выведется соотвтетсвующее собщение и тест будет помечен как проваленный. Там еще есть много других методов, начинающихся с assert, для проверки массивов, объектов, проверки что функция выкидывает исключение или генерирует ошибку. |
|
|
Каждый метод, имя которого начинается с `test…`, будет выполнен. Также, вы можете добавить методы `setUp` и `tearDown`, которые будут вызываться до и после каждого теста. Выше был приведен пример теста на основе PhpUnit. |
|
|
|
|
|
Запустить тест можно командой |
|
|
|
|
|
php phpunit.phar FunctionCountTest.php |
|
|
php phpunit.phar TruncateTest.php |
|
|
|
|
|
PhpUnit выполнит его и выведет результаты. Если у тебя много тестов, можно указать только имя папки и phpUnit сам найдет все файлы в ней, имена которых заканчиваются на `Test.php` и выполнит. |
|
|
PhpUnit выполнит его и выведет результаты. Если у вас много тестов, можно указать только имя папки и phpUnit сам найдет все файлы в ней, имена которых заканчиваются на `…Test.php` и выполнит их. |
|
|
|
|
|
Если ты тестируешь существующий код, то часто что-то требуется сделать до выполнения тестов, например, подключить автозагрузчик или задать значение какой-то переменной. Для этого можо создать файл, например, bootstrap.php. Если ты используешь композер, то подключение автозагрузки делается одной строчкой: |
|
|
Если вы тестируете существующий код, то часто что-то требуется сделать до выполнения тестов, например, подключить автозагрузчик или задать значение какой-то переменной. Для этого можо создать файл, например, bootstrap.php. Если вы используете композер, то подключение автозагрузки делается одной строчкой: |
|
|
|
|
|
```php |
|
|
require_once '../vendor/autoload.php'; |
|
|
``` |
|
|
|
|
|
Если нет, то потребуется чуть больше кода. После этого, мы можем указать phpunit подключить этот файл с помощью опции `--bootstrap`: |
|
|
|
|
|
php phpunit.phar --bootstrap bootstrap.php FunctionCountTest.php |
|
|
php phpunit.phar --bootstrap bootstrap.php TruncateTest.php |
|
|
|
|
|
Обычно для тестов создают папку с названием tests в корне проекта. |
|
|
|
|
|
@@ -205,7 +224,7 @@ require_once '../vendor/autoload.php'; |
|
|
|
|
|
php phpunit.phar |
|
|
|
|
|
Подвох: phpunit при выполнении тестов перехватывает и скрывает все, что выводится с помощью echo и аналогичных функций. Если тебе надо что-то вывести для отладки, используй конструкцию вроде `var_dump($x); die();`. |
|
|
Подвох: phpunit при выполнении тестов перехватывает и скрывает все, что выводится с помощью echo и аналогичных функций. Если вам надо что-то вывести для отладки, используй конструкцию вроде `var_dump($x); die();`. |
|
|
|
|
|
Ссылки про phpUnit: |
|
|
|
|
|
@@ -220,13 +239,11 @@ phpunit интегрируется в IDE: |
|
|
- [Netbeans](https://netbeans.org/kb/docs/php/phpunit_ru.html) (я подозреваю, что можно обойтись без установки PEAR, достаточно указать путь к phpunit.phar) |
|
|
- PhpStorm, [мануал](https://www.jetbrains.com/phpstorm/help/enabling-phpunit-support.html#d568329e265) (англ.) — достаточно нажать в настройках кнопку скачивания phpunit.phar |
|
|
|
|
|
В этом случае ты можешь запускать и просматривать результаты тестов прямо в IDE. Но учиться лучше с использованием командной строки. |
|
|
В этом случае вы можете запускать и просматривать результаты тестов прямо в IDE. Но учиться лучше с использованием командной строки. |
|
|
|
|
|
### Codeception |
|
|
|
|
|
[Cайт codeception](http://codeception.com/). Этот фреймворк заточен на написание API и GUI тестов (хотя он включает в себя phpunit и может выполнять его тесты, но удобнее их хранить отдельно). Он может работать как с примитивным html-браузером на основе Symfony BrowserKit (не интерпретирующим CSS и JS), так и с PhantomJS и Selenium. Также, он может использоваться для «функционального» тестирования, то есть вызова контроллеров напрямую (не через запрос на веб-сервер). Для этого у него есть плагины к разным популярным фреймворкам. Причем синтаксис скриптов для всех этих случаев примерно одинаков. |
|
|
|
|
|
~~Подвох: codeception выполняет каждый скрипт 2 раза~~ (это было раньше, сейчас это исправлено). Если ты пытаешься в скрипте определить функцию или класс, ты получишь из-за этого ошибку. Создавай классы и функции во внешнем файле, подключаемом через `require_once`. |
|
|
[Cайт codeception](http://codeception.com/). Этот фреймворк заточен на написание API и GUI тестов (хотя он включает в себя phpunit и может выполнять его тесты, но удобнее их хранить отдельно). Он может работать как с примитивным html-браузером на основе Symfony BrowserKit (не интерпретирующим CSS и JS), так и с PhantomJS и Selenium. Также, он может использоваться для «функционального» тестирования, то есть вызова контроллеров фреймворка напрямую (без запуска веб-сервера и использования HTTP). Для этого у него есть плагины к разным популярным фреймворкам. Причем синтаксис скриптов для всех этих случаев примерно одинаков. |
|
|
|
|
|
Codeception, как и phpUnit, распространяется в виде одного файла codecept.phar. После скачивания можно запустить команду |
|
|
|
|
|
@@ -265,12 +282,12 @@ $I->seeInDatabase('users', array('email' => '[email protected]')); |
|
|
|
|
|
Как я уже писал выше, этот скрипт может фактически работать с использованием разных уровней эмуляции браузера (первый способ самый быстрый и простой, последний самый точный и мощный, но медленный): |
|
|
|
|
|
- вызывать напрямую контроллер, если твое приложение использует поддерживаемый фреймворк (поддерживаются ZF1-2, Yii1-2, Symfony2, Silex. Slim не поддерживается, никто не желает написать плагин и выложить в опенсорс?) |
|
|
- вызывать напрямую контроллер, если ваше приложение использует поддерживаемый фреймворк (поддерживаются ZF1-2, Yii1-2, Symfony2, Silex. Slim не поддерживается, никто не желает написать плагин и выложить в опенсорс?) |
|
|
- используя PhpBrowser, то есть скачивание HTML-страниц через HTTP |
|
|
- контролируя PhantomJS через WebDriver |
|
|
- контролируя реальный браузер через Selenium |
|
|
|
|
|
В codeception есть много удобных вспомогательных функций для заполнения форм, отправки файлов, поиска элементов на странице с помощью XPath и CSS селекторов, работы с куками, заголовками, аякс-запросами, всплывающими окнами, ифреймами, снятия скриншотов, навигации. Эти функции разбиты на модули (например, модуль для тестирования АПИ, модуль для работы с базой данных), и ты можешь писать свои или расширять существующие модули через наследование. |
|
|
В codeception есть много удобных вспомогательных функций для заполнения форм, отправки файлов, поиска элементов на странице с помощью XPath и CSS селекторов, работы с куками, заголовками, аякс-запросами, всплывающими окнами, ифреймами, снятия скриншотов, навигации. Эти функции разбиты на модули (например, модуль для тестирования АПИ, модуль для работы с базой данных), и вы можете писать свои или расширять существующие модули через наследование. |
|
|
|
|
|
Ссылки: |
|
|
|
|
|
@@ -279,49 +296,11 @@ $I->seeInDatabase('users', array('email' => '[email protected]')); |
|
|
- http://habrahabr.ru/post/146662/ (видео-скринкаст на 20 минут) |
|
|
- http://habrahabr.ru/post/140344/ |
|
|
|
|
|
### Skipfish |
|
|
|
|
|
[Skipfish](http://code.google.com/p/skipfish/) (англ.) — инструмент от Google, который может использоваться для поиска ошибок на сайте и заодно для нагрузочного тестирования. Он обходит все страницы, начиная со стартовой и перемещаясь по ссылкам, и позволяет обнаруживать битые ссылки (в том числе на картинки, CSS и JS файлы). Также, он умеет отправлять запросы со случайно сгенерированными данными и пытается искать явные XSS/SQL уязвимости. Он работает очень быстро (если конечно сайт может отвечать быстро). |
|
|
|
|
|
Skipfish — это не совсем средство автоматического тестирования, так как результаты работы выдаются в виде html-отчета, но он может быть полезен например для поиска ошибок на существующем сайте. |
|
|
|
|
|
Skipfish генерирует большую нагрузку на сайт и шлет очень много запросов, потому применяй его только на своих сайтах. |
|
|
|
|
|
### PhantomJS |
|
|
|
|
|
[PhantomJS](http://phantomjs.org/) — это браузерный движок (используется Webkit — тот же, что используется в Safari, Opera, Яндекс-браузере и старых версиях Хрома), которым можно управлять с помощью скриптов на яваскрипте. Это headless браузер, то есть он не выводит никаких окон (и вообще не требует наличия видеокарты и дисплея), а работает как приложение командной строки. Он кроссплатформенный и его можно запускать, например, автоматически на линукс сервере. Он умеет переходить по страницам, загружать CSS/JS (при желании и картинки), делать скриншоты, выполнять произвольный JS код в контексте страницы. |
|
|
|
|
|
Также, для PhantomJS есть плагин ghostdriver (WebDriver), который позволяет подсоединиться к программе извне и управлять ей. Он использует протокол Selenium, и с его помощью PhantomJS можно управлять из codeception. |
|
|
|
|
|
Тесты по идее можно писать на яваскрипте, скармливая их напрямую PhantomJS, но удобнее использовать какую-нибудь библиотеку работающую поверх него, например, [Casper.js](http://casperjs.org/) (это если ты готов писать тесты на явскрипте, если на PHP, то стоит использовать codeception + PhantomJS через WebDriver). |
|
|
|
|
|
Для повышения скорости работы теста стоит отключить загрузку картинок, если они не требуются для теста. |
|
|
|
|
|
Статьи по использованию PhantomJS с codeception наверно нетрудно нагуглить. |
|
|
|
|
|
### Selenium |
|
|
|
|
|
[Selenium](http://www.seleniumhq.org/) — это проект, предоставляющий драйвера для разных браузеров, которые встраиваются в них и позволяют управлять ими. Также, Selenium содержит сервер, который позволяет управлять большим числом разных браузеров ии распределять задания между ними. |
|
|
|
|
|
Selenium сервер написан на Яве, потому она понадобится чтобы его запустить. Поддерживаются браузеры Firefox, IE (6-11), Safari на OS X, Opera 12 (старая Опера), Chrome. |
|
|
|
|
|
Selenium дает наиболее полноценное тестирование, так как ты можешь запускать код в конкретной версии браузера (например, IE) под конкретной ОС. Но его настройка сложнее чем других инструментов, и он требует больше ресурсов. Когда выполняется тест, браузер должен быть запущен и ты не можешь пользоваться компьютером, так как один лишний клик может сорвать выполнение теста. По этой причине для тестов обычно поднимают сеть вирутальных машин, в которых тесты и выполняются. |
|
|
|
|
|
Так как настроить окружение для запуска тестов сложно, есть коммерческие сервисы (например saucelabs) которые за плату выполняют selenium-тесты на нужных браузерах и возвращают результат. Они предоставляют API с помощью которого тесты можно запускать автоматически и умеют отслеживать изменения в репозитории, тестируя код при каждом новом коммите. |
|
|
|
|
|
Тесты в браузере содержат подвохи: например, когда ты программно нажимаешь кнопку, браузеру нужно время, чтобы выполнить привязанный к ней яваскрипт, обработать изменения в DOM, перерисовать экран. Если твой скрипт не будет дожидаться этого, а попробует сразу после нажатия кнопки проверить изменения на экране, он может их не увидеть. В некоторых статьях ты можешь увидеть совет вроде «делать паузу N мс после каждого шага», но это плохие советы. Во-первых, нет гарантий, что действие выполнится за эти N мс, во-вторых, это сильно тормозит тесты. Лучше, как советует Яндекс, в таких случаях периодически проверять появление определенного элемента на странице. |
|
|
|
|
|
Также, не так просто проверить, что элемент видим. Ведь в CSS много свойств (`opacity`, `visisbility`, `display`), которыми можно его скрыть, плюс он может быть помещен за пределами экрана. |
|
|
|
|
|
Тесты в браузере могут быть хрупкими. У браузера может выскочить окно обновления, может произойти ошибка при загрузке какого-то внешнего ресурса, в общем, сложностей тут много. А кто говорил, что будет легко? |
|
|
|
|
|
Также, Selenium содержит плагин к фаерфоксу (Selenium IDE), который позволяет записывать действия пользователя и генерировать из них тест (то есть повторять эти действия позже), но он, как я понимаю, довольно слабый и генерирует тяжелочитаемый код на своем странном языке. Гораздо лучше управлять Selenium из codeception и писать тесты на PHP. |
|
|
|
|
|
Статьи: |
|
|
### Behat, phpspec |
|
|
|
|
|
- отличная статья от Яндекса http://habrahabr.ru/company/yandex/blog/173769/ |
|
|
- http://habrahabr.ru/post/152653/ |
|
|
Библиотеки для написания тестов в стиле BDD: http://docs.behat.org/en/v2.5/ (англ), http://www.phpspec.net/ |
|
|
|
|
|
## Тестирование JS кода |
|
|
|
|
|
### Mocha |
|
|
|
|
|
@@ -379,7 +358,7 @@ describe('Пользователь заходит на страницу реги |
|
|
|
|
|
### Jasmine |
|
|
|
|
|
[Jasmine](http://jasmine.github.io/) (англ.) - это тоже фреймворк для тестирования JS-кода с уклоном в BDD (Behaviour-Driven Development). Если ты забыл, то идея BDD в том, что мы до разработки описываем требования (спецификацию) к коду в виде тестов. Он позволяет писать простые, легко читаемые тесты. Запускать тесты можно как через браузер (если ты хочешь смотреть релуьтаты глазами), так и из командной строки с помощью Node.JS (если проверку надо автоматизировать). Если твои тесты используют взаимодействие с DOM (или какие-то другие компоненты браузера) то для запуска под Node.JS придется подключить упомянутый выше JSDOM. Вот пример простого теста на Jasmine, которым мы протестируем функцию вычисления квадратного корня `Math.sqrt()`: |
|
|
[Jasmine](http://jasmine.github.io/) (англ.) - это тоже фреймворк для тестирования JS-кода с уклоном в BDD (Behaviour-Driven Development). Если вы забыл, то идея BDD в том, что мы до разработки описываем требования (спецификацию) к коду в виде тестов. Он позволяет писать простые, легко читаемые тесты. Запускать тесты можно как через браузер (если вы хочете смотреть релуьтаты глазами), так и из командной строки с помощью Node.JS (если проверку надо автоматизировать). Если твои тесты используют взаимодействие с DOM (или какие-то другие компоненты браузера) то для запуска под Node.JS придется подключить упомянутый выше JSDOM. Вот пример простого теста на Jasmine, которым мы протестируем функцию вычисления квадратного корня `Math.sqrt()`: |
|
|
|
|
|
```js |
|
|
describe("Math.sqtr() это функция", function() { |
|
|
@@ -403,11 +382,52 @@ describe("Math.sqtr() это функция", function() { |
|
|
|
|
|
 |
|
|
|
|
|
Jasmine расширяемый и ты можешь дописывать свои проверяльщики (matchers) и свой код для вывода результатов в удобном тебе виде. |
|
|
Jasmine расширяемый и вы можете дописывать свои проверяльщики (matchers) и свой код для вывода результатов в удобном вам виде. |
|
|
|
|
|
### Behat, phpspec |
|
|
## Дополнительные инструменты |
|
|
|
|
|
Библиотеки для написания тестов в стиле BDD: http://docs.behat.org/en/v2.5/ (англ), http://www.phpspec.net/ |
|
|
### Skipfish |
|
|
|
|
|
[Skipfish](http://code.google.com/p/skipfish/) (англ.) — инструмент от Google, который может использоваться для поиска ошибок на сайте и заодно для нагрузочного тестирования. Он обходит все страницы, начиная со стартовой и перемещаясь по ссылкам, и позволяет обнаруживать битые ссылки (в том числе на картинки, CSS и JS файлы). Также, он умеет отправлять запросы со случайно сгенерированными данными и пытается искать явные XSS/SQL уязвимости. Он работает очень быстро (если конечно сайт может отвечать быстро). |
|
|
|
|
|
Skipfish — это не совсем средство автоматического тестирования, так как результаты работы выдаются в виде html-отчета, но он может быть полезен например для поиска ошибок на существующем сайте. |
|
|
|
|
|
Skipfish генерирует большую нагрузку на сайт и шлет очень много запросов, потому применяй его только на своих сайтах. |
|
|
|
|
|
### PhantomJS |
|
|
|
|
|
[PhantomJS](http://phantomjs.org/) — это браузерный движок (используется Webkit — тот же, что используется в Safari, Opera, Яндекс-браузере и старых версиях Хрома), которым можно управлять с помощью скриптов на яваскрипте. Это headless браузер, то есть он не выводит никаких окон (и вообще не требует наличия видеокарты и дисплея), а работает как приложение командной строки. Он кроссплатформенный и его можно запускать, например, автоматически на линукс сервере. Он умеет переходить по страницам, загружать CSS/JS (при желании и картинки), делать скриншоты, выполнять произвольный JS код в контексте страницы. |
|
|
|
|
|
Также, для PhantomJS есть плагин ghostdriver (WebDriver), который позволяет подсоединиться к программе извне и управлять ей. Он использует протокол Selenium, и с его помощью PhantomJS можно управлять из codeception. |
|
|
|
|
|
Тесты по идее можно писать на яваскрипте, скармливая их напрямую PhantomJS, но удобнее использовать какую-нибудь библиотеку работающую поверх него, например, [Casper.js](http://casperjs.org/) (это если вы готов писать тесты на явскрипте, если на PHP, то стоит использовать codeception + PhantomJS через WebDriver). |
|
|
|
|
|
Для повышения скорости работы теста стоит отключить загрузку картинок, если они не требуются для теста. |
|
|
|
|
|
Статьи по использованию PhantomJS с codeception наверно нетрудно нагуглить. |
|
|
|
|
|
### Selenium |
|
|
|
|
|
[Selenium](http://www.seleniumhq.org/) — это проект, предоставляющий драйвера для разных браузеров, которые встраиваются в них и позволяют управлять ими. Также, Selenium содержит сервер, который позволяет управлять большим числом разных браузеров ии распределять задания между ними. |
|
|
|
|
|
Selenium сервер написан на Яве, потому она понадобится чтобы его запустить. Поддерживаются браузеры Firefox, IE (6-11), Safari на OS X, Opera 12 (старая Опера), Chrome. |
|
|
|
|
|
Selenium дает наиболее полноценное тестирование, так как вы можете запускать код в конкретной версии браузера (например, IE) под конкретной ОС. Но его настройка сложнее чем других инструментов, и он требует больше ресурсов. Когда выполняется тест, браузер должен быть запущен и вы не можете пользоваться компьютером, так как один лишний клик может сорвать выполнение теста. По этой причине для тестов обычно поднимают сеть вирутальных машин, в которых тесты и выполняются. |
|
|
|
|
|
Так как настроить окружение для запуска тестов сложно, есть коммерческие сервисы (например saucelabs) которые за плату выполняют selenium-тесты на нужных браузерах и возвращают результат. Они предоставляют API с помощью которого тесты можно запускать автоматически и умеют отслеживать изменения в репозитории, тестируя код при каждом новом коммите. |
|
|
|
|
|
Тесты в браузере содержат подвохи: например, когда вы программно нажимаете кнопку, браузеру нужно время, чтобы выполнить привязанный к ней яваскрипт, обработать изменения в DOM, перерисовать экран. Если ваш скрипт не будет дожидаться этого, а попробует сразу после нажатия кнопки проверить изменения на экране, он может их не увидеть. В некоторых статьях вы можете увидеть совет вроде «делать паузу N мс после каждого шага», но это плохие советы. Во-первых, нет гарантий, что действие выполнится за эти N мс, во-вторых, это сильно тормозит тесты. Лучше, как советует Яндекс, в таких случаях периодически проверять появление определенного элемента на странице. |
|
|
|
|
|
Также, не так просто проверить, что элемент видим. Ведь в CSS много свойств (`opacity`, `visisbility`, `display`), которыми можно его скрыть, плюс он может быть помещен за пределами экрана. |
|
|
|
|
|
Тесты в браузере могут быть хрупкими. У браузера может выскочить окно обновления, может произойти ошибка при загрузке какого-то внешнего ресурса, в общем, сложностей тут много. А кто говорил, что будет легко? |
|
|
|
|
|
Также, Selenium содержит плагин к фаерфоксу (Selenium IDE), который позволяет записывать действия пользователя и генерировать из них тест (то есть повторять эти действия позже), но он, как я понимаю, довольно слабый и генерирует тяжелочитаемый код на своем странном языке. Гораздо лучше управлять Selenium из codeception и писать тесты на PHP. |
|
|
|
|
|
Статьи: |
|
|
|
|
|
- отличная статья от Яндекса http://habrahabr.ru/company/yandex/blog/173769/ |
|
|
- http://habrahabr.ru/post/152653/ |
|
|
|
|
|
### Travis CI |
|
|
|
|
|
@@ -440,11 +460,11 @@ Jasmine расширяемый и ты можешь дописывать сво |
|
|
- https://github.com/Verpul/uppu.ru (на F3 framework) |
|
|
- https://github.com/dKab/download.me (на Slim, но почему-то не использует композер. Это придется исправить) |
|
|
|
|
|
Ты форкаешь тот, который тебе больше нравится (или меньше не нравится), и мы пишем под него юнит-тесты на phpUnit и интерфейсные тесты на codeception. |
|
|
вы форкаете тот, который вам больше нравится (или меньше не нравится), и мы пишем под него юнит-тесты на phpUnit и интерфейсные тесты на codeception. |
|
|
|
|
|
Если тебе не нравится файлообменник, можно потестировать что-то еще (если есть идеи небольшого приложения на PHP, требующего тестов — напишите). |
|
|
Если вам не нравится файлообменник, можно потестировать что-то еще (если есть идеи небольшого приложения на PHP, требующего тестов — напишите). |
|
|
|
|
|
Прежде чем писать тесты, надо составить план тестирования (что мы тестируем и как). Мы сначала определяем, какие возможности предоставляет приложение, а потом для каждой пишем несколько тест кейсов. Не забывай, что надо тестировать как позитивные, так и негативные сценарии. Вот примерный план, 1 пункт = 1 тест. |
|
|
Прежде чем писать тесты, надо составить план тестирования (что мы тестируем и как). Мы сначала определяем, какие возможности предоставляет приложение, а потом для каждой пишем несколько тест кейсов. Не забывайте, что надо тестировать как позитивные, так и негативные сценарии. Вот примерный план, 1 пункт = 1 тест. |
|
|
|
|
|
- **Загрузка файла** |
|
|
- Загрузить файл и убедиться что он загрузился |
|
|
@@ -471,7 +491,7 @@ Jasmine расширяемый и ты можешь дописывать сво |
|
|
|
|
|
В качестве базы для тестов стоит использовать in-memory mysql базу. |
|
|
|
|
|
Если у тебя есть какие-то дополнения к плану, можно их внести. |
|
|
Если у вас есть какие-то дополнения к плану, можно их внести. |
|
|
|
|
|
Что тестировать юнит-тестами? Ими можно тестировать например функцию валидации (комментария к примеру), а также функции вроде форматирования размера файла (которые выводят его в виде «12Мб»). |
|
|
|
|
|
|