重用黄瓜步骤


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
万一有人感到困惑,这里的每个人都忽略了在Ruby步骤定义中do启动该do...end块的要求。实际上这是必需的。
肖恩·勒布朗

Answers:


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 2011年

1
@BrendanDean接受此答案后,该steps方法不存在。请参阅下面的答案。
michaeltwofish

请注意,连接步骤现在被视为反模式,应避免使用。见黄瓜维基- cucumber.io/docs/guides/anti-patterns/...
扬Molak

103

请注意,在最新版本的黄瓜中,用于在步骤中调用步骤的方法已发生变化,您会看到是否收到类似“警告:不赞成在步骤定义中使用'Given / When / Then'的错误,请使用'step'而是调用其他步骤:/path/to/step_definitions/foo_steps.rb:631:in'在'块中。有关详细信息,请参见黄瓜Wiki

更改的要点是您现在应该使用stepor 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
值得的是,在使用Cucumber之后,我建议完全不使用步骤中的步骤。问题很难发现,实际上使维护变得更加困难。而是使用辅助方法。
michaeltwofish

2
也许您应该将此评论添加到您的答案中,因为它的投票率很高,而且仍然获得投票。它将帮助人们注意到这一信息
Andrei Botalov

嗨@ michaeltwofish,2017年有什么变化吗?我收到syntax error, unexpected tIDENTIFIER, expecting keyword_end stackoverflow.com/questions/43319331/…–
ericn

43

从步骤定义中调用步骤是一种不好的做法,并且有一些缺点

  1. 如果场景将失败并且存在嵌套的步骤调用,则您只会在堆栈跟踪中获得最后调用的步骤定义。可能很难找到从哪个地方调用了上一个stepdef
  2. 有时比ruby方法更难找到和阅读对stepdef的调用
  3. 与从step defs调用步骤相比,Ruby方法具有更多的功能

AslakHellesøy 建议将流行的动作提取到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

这是黄瓜邮件列表中有关此主题的有用讨论- 链接


2
我确实相信,由于上述相同的原因,这种方法比调用step或steps函数要好得多。
pisaruk

2
这还有另一个好处。使用Idea(或Rubymine),您可以轻松跳转到函数定义,但不能跳转到%{...}步骤中的步骤。

同样,此设置遵循DRY原理
Sorcerer86pt

2
尽管我遇到了重复使用步骤的问题,但我认为这很糟糕。登录只是不同步骤的总和:“访问某些内容”,“填充某些内容”。自然的方法是重用步骤,而不是将每个步骤转换为对函数的调用。IMO,应该改进步骤中的步骤。
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

在功能文件中重用关键字,这将提供代码可重用性。

强烈建议不要在步骤def中调用步骤def。

我会这样写我的功能文件,

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
    }
}

这样,就有很多代码可重用性。您相同的“给定”和“然后”处理有效和无效方案。同时,您的功能文件对读者来说很有意义。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.