// codeart.ru / Вопрос/Ответ / Как правильно писать тесты на RSpec? Форум

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

Автор: Evgeniy Sergeev

В этом топике я предлагаю обсудить то как лучше создавать тесты с использованием фреймворка RSpec. Я не буду останавливаться на том что такое Rspec, откуда он появился, зачем нужен и так далее. Те кто программирует на Ruby скорее всего о нем слышали, а если нет, то предлагаю ознакомиться с базовыми понятиями самостоятельно. Далее я расскажу о моем представлении того как должны быть организованы тесты.

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

Я прочитал достаточно много статей на тему написания тестов с помощью Rspec, а так же просмотрел реальные проекты, которые используют его в своей работе. В итоге у меня сформировалось свое понимание того, какой должна быть структура теста (блоки describe и it). Оно во много совпадает с общепринятыми подходами, но имеет так же и свои отличия. Я не утверждаю, что это единственно верный подход, но тем не менее считаю, что он тоже имеет право на жизнь. Если у Вас другая точка зрения, то очень интересно обсудить ее в комментариях.

Первое, что хочется отметить — это то, что блоки «описания» (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)

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

Задаем правильные вопросы

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

  1. Какие данные должны содержаться в классе?
  2. Какие действия должны выполняться над этими данными?
  3. Какие результаты должны быть получены при штатном функционировании?
  4. Какой результат должен быть получен в случае ошибки во входных данных?

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

Заключение

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

Жду ваших комментариев.

  1. Интересный и логичный подход.

    Вопрос по Cucumber + RSpec:
    Какие тесты писать в огурце, а какие в спеках?

    Я пока пришел к тому что в огурце — контроллеры и представления, в спеках — модели.

    Хотелось бы найти для себя правильное правило и следовать ему.

  2. Честно говоря, я пришел к выводу, что для моих задач вполне достаточно rspec, огурец не использую совсем. Обсудить это можно — вот здесь

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

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

  5. To Evgeny Sergeev

    Найдите пожалуйста слова «так не делается» в моем комментарии. Суть комментария даже далека от этих слов.

  6. Dmitry, слов «так не делается» в Вашем комментарии нет. Как это изменяет то, что я написал?

Leave a Reply

« »