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

Я хочу повторно использовать некоторые шаги 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

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

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


person Daniel Huckstep    schedule 27.05.2009    source источник
comment
На случай, если кто-то запутается, все здесь не учитывают do, необходимый для запуска блока do...end в определении шага Ruby. На самом деле это необходимо.   -  person Shaun Lebron    schedule 28.10.2014


Ответы (5)


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

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
person tomafro    schedule 28.05.2009
comment
Еще проще вставить код огурца так: steps %Q{Given I am logged in} - person BrendanDean; 09.08.2011
comment
@BrendanDean Когда этот ответ был принят, метода steps не существовало. Смотрите мой ответ ниже. - person michaeltwofish; 07.12.2011
comment
Обратите внимание, что шаги соединения теперь считаются антипаттерном, и их следует избегать. См. Вики по Cucumber - cucumber.io/docs/guides/ антипаттерны / - person Jan Molak; 11.10.2019

Обратите внимание, что метод вызова шагов внутри шагов был изменен в последних версиях огурца, что вы увидите, если получите сообщение об ошибке типа «ПРЕДУПРЕЖДЕНИЕ: использование« Дано / Когда / Тогда »в определениях шагов устарело, используйте« шаг », чтобы вместо этого вызовите другие шаги: /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
person michaeltwofish    schedule 06.12.2011
comment
Как бы то ни было, после большего количества времени с огурцом, я рекомендую вообще не использовать шаги за шагом. Проблемы сложно отследить, и это действительно затрудняет обслуживание. Вместо этого используйте вспомогательные методы. - person michaeltwofish; 11.10.2012
comment
Возможно, вам стоит включить этот комментарий в свой ответ, так как он очень популярен и все еще получает голоса. Это поможет людям заметить эту информацию - person Andrei Botalov; 25.12.2012
comment
привет @michaeltwofish, есть ли какие-нибудь изменения в этом в 2017 году? Я получаю syntax error, unexpected tIDENTIFIER, expecting keyword_end stackoverflow.com/questions/43319331/ - person ericn; 02.05.2017

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

  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 - ссылка

person Andrei Botalov    schedule 02.03.2012
comment
Я считаю, что этот подход намного лучше, чем вызов функций step или steps по тем же причинам, о которых говорилось выше. - person Pikachu; 26.11.2012
comment
В этом есть еще одно преимущество. Используя Idea (или Rubymine), вы можете легко перейти к определениям функций, но не к шагам в шагах% {...}. - person slipset; 10.12.2012
comment
также эта установка следует принципу СУХОЙ - person Sorcerer86pt; 31.05.2013
comment
Хотя я столкнулся с проблемой повторного использования шагов, я думаю, что это просто плохо. Вход - это просто сумма разных шагов: что-то зайти, что-то заполнить. Естественным путем было бы повторное использование шагов вместо преобразования каждого шага в вызов функции. ИМО, вызов шагов внутри шагов нужно просто улучшить. - person dgmora; 27.06.2013

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

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
person Rimian    schedule 21.02.2012
comment
Это должен был быть комментарий, а не ответ. - person Kelvin; 21.02.2013

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

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

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

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 обрабатывают как допустимые, так и недопустимые сценарии. В то же время ваш файл характеристик имеет смысл для читателей.

person LINGS    schedule 30.05.2013