вторник, 20 ноября 2012 г.

Как правильно писать тесты на RSpec?


Структура описания теста

Первое, что хочется отметить – это то, что блоки “описания” (describe) могут и должны быть вложенными, это позволяет достаточно подробно структурировать тест. При написании теста я всегда руководствуюсь тем, что при запуске rspec с ключом “-f s” должна отображаться готовая спецификация к тесту. Поэтому в блоке “описания” я описываю одну конкретную функцию, которая должна быть реализована (например, “сохраняет новую статью в базе данных”).

Обычно в первую очередь я создаю структур теста содержащего только блоки “описания” (describe), а только потом эти блоки наполняю их конкретными предположениями (блоками IT). Вот пример такой структуры:
describe "Article" do 
describe "структура" do
end

describe "сохранение статьи в БД" do
end

describe "удаление из БД по заданному ID" do
end

describe "поиск статьи по заданному id в БД" do
end
end

После того, как основные функции класса описаны, я перехожу к описанию “предположений” (блокам IT) в которых отражаются конкретные особенности функционирования класса. Здесь так же в первую очередь идет описание всех “предположений”, без реализации:

describe "Article" do
describe "структура" do
it "должна содержать поле title"
it "должна содержать поле content"
end
describe "сохранение статьи в БД" do
it "при длине поля title более 255 символов должно выбрасываться исключение"
it "при пустом поле title должно выбрасываться исключение"
it "при длине поля content более 65535 символов должно выбрасываться исключение"
it "при пустом поле content должно выбрасываться исключение"
it "при наличии в поле content стоп слов должно выбрасываться исключение"
it "при успешном сохранении статьи должен возвращаться объект типа Article"
end
describe "удаление из БД по заданному ID" do
it "при успешном удалении должно возвращаться значение TRUE"
it "при не успешном удалении должно выбрасываться исключение"
end
describe "поиск статьи по заданному id в БД" do
it "для существующего ID должен возвращаться объект Article"
it "для несуществующего ID должно выбрасываться исключение"
end
end

Хочу обратить внимание, что на данном этапе блоки IT не имеют реализации, поэтому при запуске теста они будут помечены как “(PENDING: Not Yet Implemented)”. В итоге запуск команды “spec -f s ./spec.rb” выдаст следующую спецификацию:

Article структура
- должна содержать поле title (PENDING: Not Yet Implemented)
- должна содержать поле content (PENDING: Not Yet Implemented)
Article сохранение статьи в БД
- при длине поля title более 255 символов должно выбрасываться исключение (PENDING: Not Yet Implemented)
- при пустом поле title должно выбрасываться исключение (PENDING: Not Yet Implemented)
- при длине поля content более 65535 символов должно выбрасываться исключение (PENDING: Not Yet Implemented)
- при пустом поле content должно выбрасываться исключение (PENDING: Not Yet Implemented)
- при наличии в поле content стоп слов должно выбрасываться исключение (PENDING: Not Yet Implemented)
- при успешном сохранении статьи должен возвращаться объект типа Article (PENDING: Not Yet Implemented)
Article удаление из БД по заданному ID
- при успешном удалении должно возвращаться значение TRUE (PENDING: Not Yet Implemented)
- при не успешном удалении должно выбрасываться исключение (PENDING: Not Yet Implemented)
Article поиск статьи по заданному id в БД
- для существующего ID должен возвращаться объект Article (PENDING: Not Yet Implemented)
- для несуществующего ID должно выбрасываться исключение (PENDING: Not Yet Implemented)

После того как спецификация получена, можно приступать к конкретной реализации теста.

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

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

Из описания теста, указанного выше, видно, что на первый вопрос ответ дается в разделе “Article структура”, на второй вопрос отвечают названия всех остальных блоков describe, а не третий и четвертый вопросы отвечает содержимое блоков IT.

воскресенье, 18 ноября 2012 г.

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

Selenium WebDriver – это не инструмент для автоматизации тестирования.
Итак, что такое Selenium WebDriver?

По назначению Selenium WebDriver представляет собой драйвер браузера, то есть программную библиотеку, которая позволяет разрабатывать программы, управляющие поведением браузера.

По своей сущности Selenium WebDriver представляет собой:
  • спецификацию программного интерфейса для управления браузером,
  • референсные реализации этого интерфейса для нескольких браузеров,
  • набор клиентских библиотек для этого интерфейса на нескольких языках программирования.

Теперь понятно, почему бессмысленно сравнивать Selenium WebDriver с «другими инструментами тестирования». Selenium WebDriver – это драйвер браузера

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

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

Исходя из этого определения, ясно, что WebDriver не имеет прямого отношения к тестированию. Он всего лишь предоставляет автотестам доступ к браузеру. На этом его функции заканчиваются.

Структурирование, группировку и запуск тестов, а также генерацию отчётов о тестировании, обеспечивает фреймворк тестирования в нашем случае RSpec или Cucumber для Ruby. Разработка тестов ведётся в среде RubyMine (либо любой текстовый редактор). Запуск тестов по расписанию и публикацию отчётов выполняет сервер непрерывной интеграции – CruiseControl. И всё это – самостоятельные инструменты, не имеющие отношения к проекту Selenium.


Впрочем, в рамках проекта Selenium разрабатывается не только драйвер, но ещё несколько сопутствующих продуктов – Selenium Server позволяет организовать удалённый запуск браузера, при помощи Selenium Grid можно построить кластер из Selenium-серверов. Они встают в один ряд с вышеперечисленными инструментами и фреймворками, потому что также участвуют в построении системы запуска тестов. Кроме того, имеется «рекордер», который называется Selenium IDE, он умеет записывать действия пользователя и генерировать код, в котором используется интерфейс WebDriver для выполнения записанных действий.

Популярные фреймворки для проектирования тестов позволяют наряду с другими драйверами использовать WebDriver. Среди таких фреймворков можно упомянуть Capybara

Серверная сторона вопроса

Для запуска интеграционных тестов потребуется:
1. Некоторая виртуальная машина ОС debian (Command-line interfaces), на которой установлено все необходимое для запуска нашего кода ПО (ruby, postgresql-client, libxml2, libxslt и т.д.)
2. Доступ до БД (для каждого проекта должна существовать некоторая пустая база)
3. X-сервер - (обеспечивает доступ по VNC к среда рабочего стола или GUI)
4. Firefox или Chrome
5. git
6. Место, куда можно склонировать из гита проекты

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