Повторно использовать шаги огурца


103

Я хочу повторно использовать некоторые шаги Cucumber, но не могу найти правильный способ.

Я хочу написать такой шаг:

Given /^I login with (.*) credentials$/ |type|
  # do stuff with type being one of "invalid" or "valid"
end

Но затем сделайте еще один шаг, например:

Given /^I login successfully$
  # call "Given I login with valid credentials"
end

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

Есть ли способ вызвать этот другой шаг, или я просто помещаю логику во вспомогательный метод и вызываю указанный метод из каждой задачи (в основном рефакторинг извлечения метода, который после прочтения моего вопроса заставляет меня поверить, что на самом деле лучший способ тем не мение)?


1
В случае, если кто-то сбит с толку, все здесь не учитывают требование, doнеобходимое для запуска do...endблока, в определении шага Ruby. На самом деле это необходимо.
Шон Леброн,

Ответы:


102

ОБНОВЛЕНИЕ : описанный ниже метод устарел. Рекомендуемый способ вызова шага из другого шага теперь выглядит так:

Given /^I login successfully$/
    step "I login with valid credentials" 
end 

Старый, устаревший метод (для справки):

Вы можете вызывать шаги из других шагов следующим образом:

Given /^I login successfully$/
  Given "I login with valid credentials"
  Then "I should be logged in"
end

Если все сценарии внутри функции требуют этого (или других шагов), вы также можете добавить фон для каждой функции, выполнив общие шаги, например:

Background:
  Given I log in with valid credentials

Scenario: Change my password
  Given I am on the account page

5
Еще проще вставить код огурца вот так:steps %Q{Given I am logged in}
BrendanDean,

1
@BrendanDean Когда этот ответ был принят, stepsметода не существовало. Смотрите мой ответ ниже.
michaeltwofish 07

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

103

Обратите внимание, что метод вызова шагов внутри шагов был изменен в последних версиях огурца, что вы увидите, если получите сообщение об ошибке типа «ПРЕДУПРЕЖДЕНИЕ: использование« Дано / Когда / Тогда »в определениях шагов устарело, используйте« шаг »для вместо этого вызовите другие шаги: /path/to/step_definitions/foo_steps.rb: 631: in `block in '". Подробности смотрите в вики по огурцам .

Суть изменения в том, что теперь вы должны использовать методы stepили steps.

When /^I make all my stuff shiny$/
  step "I polish my first thing"
end

When /^I make all my stuff shiny$/
  steps %Q{
    When I polish my first thing
    When I shine my second thing
  }
end

18
Как бы то ни было, после большего количества времени с огурцом, я рекомендую вообще не использовать шаги за шагом. Проблемы сложно отследить, и это действительно затрудняет обслуживание. Вместо этого используйте вспомогательные методы.
michaeltwofish

2
Возможно, вам стоит включить этот комментарий в свой ответ, так как он очень популярен и все еще получает голоса. Это поможет людям заметить эту информацию
Андрей Боталов

привет @michaeltwofish, есть ли какие-нибудь изменения в этом в 2017 году? Я получаю syntax error, unexpected tIDENTIFIER, expecting keyword_end stackoverflow.com/questions/43319331/…
Эрикн

43

Вызов шагов из определений шагов - плохая практика и имеет некоторые недостатки :

  1. Если сценарий завершится неудачно и есть вложенные вызовы шагов, вы получите только последнее вызванное определение шага в трассировке стека. Может быть трудно найти, откуда был вызван последний stepdef
  2. Вызов stepdef иногда труднее найти и прочитать, чем метод ruby
  3. Методы Ruby дают вам больше возможностей, чем вызов шагов из step defs

Аслак Хеллесой рекомендует извлекать популярные действия в World вместо повторного использования шагов. Он изолирует эти действия в одном месте, что упрощает поиск этого кода. Вы также можете извлекать код из обычных классов или модулей Ruby.

#/support/world_extensions.rb
module KnowsUser
  def login
    visit('/login')
    fill_in('User name', with: user.name)
    fill_in('Password', with: user.password)
    click_button('Log in')
  end

  def user
    @user ||= User.create!(:name => 'Aslak', :password => 'xyz')
  end
end
World(KnowsUser)

#/step_definitions/authentication_steps.rb
When /^I login$/ do
  login
end

Given /^a logged in user$/ do
  login
end

Вот полезное обсуждение этой темы в списке рассылки Cucumber - ссылка


2
Я считаю, что этот подход намного лучше, чем вызов функций step или steps по тем же причинам, о которых говорилось выше.
pisaruk

2
В этом есть еще одно преимущество. Используя Idea (или Rubymine), вы можете легко перейти к определениям функций, но не к шагам в шагах% {...}.
слипсет

также эта установка следует принципу DRY
Sorcerer86pt

2
Хотя я столкнулся с проблемой повторного использования шагов, я думаю, что это просто плохо. Логин - это просто сумма различных шагов: «посетить что-то», «заполнить что-то». Естественным путем было бы повторное использование шагов вместо преобразования каждого шага в вызов функции. ИМО, вызов шагов внутри шагов нужно просто улучшить.
dgmora

9

Лучше всего заключать шаги в% {}, а не в кавычки. Тогда вам не нужно избегать двойных кавычек, которые вам нужно часто использовать:

Given /^I login successfully$
  step %{I login with valid credentials}
end

Given /^I login with (.*) credentials$/ |type|
  # do stuff with type being one of "invalid" or "valid"
end

5
Это должен был быть комментарий, а не ответ.
Кельвин

1

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

Настоятельно НЕ рекомендуется вызывать определения шагов в пределах шагов.

Я бы написал свой файл функций таким образом,

Scenario Outline: To check login functionality
    Given I login with "<username>" and "<password>"
    Then I "<may or may not>" login successfully

Examples:
    |username|password|may or may not|
    |paul    |123$    |may           |
    |dave    |1111    |may not       |

В моем определении шага (это Java)

@Given(I login with \"([^\"]*)\" and \"([^\"]*)\"$)
public void I_login_with_and(String username, String password){

   //login with username and password

}

@Then(I \"([^\"]*)\" login successfully$)
public void I_login_successully_if(String validity){

    if(validity.equals("may")){
        //assert for valid login
    }
    else
    if(validity.equals("may not")){
        //assert for invalid login
    }
}

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

Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.