Статьи

Вонючие огурцы

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

Я недавно пересматривал и реорганизовывал свои огуречные особенности с абсолютным отвращением. В свою защиту я начал писать огурцы всерьез 6-7 месяцев назад. Я не тратил на это слишком много времени. Было быстро начать работу с несколькими приложениями Rails, но я прекратил его использовать, когда обнаружил, что они становятся неуклюжими и сложными в обслуживании.

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

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

Feature: Todo item management

Scenario: Adding a todo item
    Given: I have a todo list named "Mondays list"
    When I go to the home page
    And I fill in "username" with "dave"
    And I fill in "password" with "secret"
    And I press "Log In"
    And I go to the todo page
    And I click on link "Mondays list"
    And I fill in "todo" with "Grab some milk"
    And I press "Add todo"
    Then I should see "Todo item added successfully"

Это довольно ужасно, да? Хуже, когда вы понимаете, что есть сценарии обновления и удаления.

В сторону — как работают огурцы

Прежде чем углубляться в глубину, лучше всего разобраться в том, как работает огурец. У вас есть три составные части: функция, сценарии и реализация.

Эта особенность представляет собой сценарий или, скорее, набор сценариев, написанных на корнишоне . Я могу описать только корнишон как что-то вроде уценки . Это читаемый человеком текст с определенной структурой и несколькими ключевыми словами. Чаще всего используются / известны: «Задано / Когда / Тогда».

За этими функциями у нас есть реализации, написанные на Ruby и более часто называемые шагами. Каждая строка сценария соответствует блоку кода Ruby. Например, Given: I have a todo list named "Mondays list"

 Given /^I have a todo list named "([^"]*)"$/ do |list_name|
  List.create(:name => list_name)
end

Проще говоря, когда запускается Cucumber, он черпает строки в наших сценариях и вызывает соответствующий блок шагов.

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

Рассекать огурец

Читая сценарий в начале статьи, я прочитал этот тест примерно на треть и потерял желание жить. Описывает ли оно поведение приложения? Ну, для меня все, что он описывает, это механика того, что я хочу сделать. Это скорее плохо написанный интеграционный тест, чем описание поведения.

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

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

Это сбивает с толку

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

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

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

Это хрупкий

Во-вторых, тест хрупкий. Что если процесс входа в систему изменится? Или URL для входа? Даже если механизм добавления элемента todo не изменился, тест не пройден. Это не может быть хорошей новостью.

Это ленивый

Последний запах — это утверждение, или «Тогда». Что это на самом деле тестирование? Рельсы вспыхивают. Это ленивое утверждение заставило меня содрогнуться.

Дураки Раш В

Со временем меня укусил огурец, и мне пришлось стать немного умнее, прежде чем торопиться с этапами рефакторинга.

Несомненно, шаги в вышеупомянутом сценарии было несложно написать. Мне почти не приходилось кодировать какие-либо шаги в Ruby (устаревший web_steps.rb сделал это для меня). Однако, если у меня есть около 20 сценариев, требующих входа пользователя в систему и изменения URL-адреса входа, у меня проблемы. Конечно, макросы Vim могут спасти часть боли, но это даже не близко к идеалу.

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

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

Делать это правильно

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

 Feature: Todo item management

I want to track items I need to do in a list. That way I will never forget them. I want to add, edit, delete and mark todo items as finished.

Огурец на самом деле предоставляет хороший синтаксис для удаления решений о том, что писать, он принимает формат «По порядку / Как / Я хочу». Я предпочитаю написать рассказ, но я мог бы легко написать:

 Feature: Todo item management
  In order to remember things
  As a person with too much on his mind
  I want to maintain todos on a list

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

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

 Feature: Todo item management

I want to track items I need to do in a list. That way I will never forget them.
I want to add, edit, delete and mark todo items as finished.
Scenario: Adding a todo item
    Given: I have a todo list named "Mondays list"
    And I am logged in as a normal user
    When I add a todo item "Grab some milk"
    Then it should be added to the todo list

Это намного лучше, но вход в систему все еще действительно беспокоит меня. Это деталь, о которой мне не стоит беспокоиться. Я говорю о добавлении элемента todo, так почему я отвлекаюсь на эту бессмыслицу? К счастью, мы можем справиться с этим, используя ключевое слово Gherkin «Background:».

 Feature: Todo item management

I want to track items I need to do in a list. That way I will never forget them. I want to add, edit, delete and mark todo items as finished.

Background:
    Given I am logged in as a normal user

Scenario: Adding a todo item
    Given: I have a todo list named "Mondays list"
    When I add a todo item "Grab some milk"
    Then it should be added to the todo list

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

 @user_logged_in
  Scenario: Adding a todo item
    Given: I have a todo list named "Mondays list"

Я могу добавить реализацию этого хука в файл поддержки вместе с другими ролями. Это особенно полезно при использовании сторонней библиотеки авторизации (такой как warden ), например так:

 Before('@user_logged_in') do
  user = User.create(name: "test_user", admin: false)
  login_as user
end

Теперь для определения шагов. Написанные на Ruby, они — настоящий бриз.

 Given /^I have a todo list named "([^"]*)"$/ do |list_name|
  @todo_list = Factory.create(:list, name: list_name)
end

When /^I add a todo item "([^"]*)"$/ do |item_description|
  visit todo_path(@todo_List)
  fill_in "Description", with: item_description
  click_button "Add Item"
end

Then /^the Item should be added to the client$/ do
  @todo_list.reload
  @todo_list.items.length.should eql 1
end

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

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

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