重复使用黄瓜的小黄瓜步骤

时间:2017-10-23 20:02:14

标签: cucumber cucumber-jvm gherkin

据我了解,基于此Given When Then wiki pageGiven步骤与应用互动以设置前提条件状态,When步骤与应用互动以尝试设置所需的新状态正在测试,Then语句读取应用程序的状态而不进行修改。

重复使用When步骤作为后续状态的Given步骤是个好主意吗?

例如,在一个简单的购物车应用程序中,我可能会写:

Given the user is interested in some item
When the user adds the item to their cart
Then the cart will include the item

Given the user adds the item to their cart
When the user checks out
Then the user will see a summary of their purchase including the item

Given the user checks out
When the user cancels an item
Then the item should be canceled
And the user should be refunded

这里有一个类似的问题reusing the user's previous interaction in a wizard,但它似乎不同意Uncle Bob's finite-state-machine interpretation,因为答案建议使步骤不那么严格,而鲍勃叔叔暗示步骤应该足够严谨从它们中制作一个可理解的状态转换图。我完全接受了从他们那里删除所有用户界面术语的建议,并只关注业务术语,但在我尝试在这里做逻辑连接业务术语之间似乎存在差异,并且只是做出逻辑上不可连接的步骤仅通过“看不见的”胶水代码连接。

4 个答案:

答案 0 :(得分:2)

所以这是一个奇怪的领域,因为它是你可以但你真的不应该做的事情之一。让我解释一下。

如你所说:

  

给定步骤与应用程序交互以设置前提条件状态

     

当步骤与应​​用程序交互以尝试设置所需的新状态时

让我们在看你的例子时牢记这一点

When the user adds the item to their cart

这一步实际上非常好,它缺乏实现语言并且描述了用户行为。 10/10

Given the user adds the item to their cart

此步骤虽然在语法上有效,但却违反了我们设置的有关GivenWhen步骤的规则。我们已经确定When用于互动,Given用于前提条件。然而,这个Given描述的是正在采取的行动,而不是状态或先决条件。写这个的更好方法可能是:

Given the user has an item in their cart

这指定了一个先决条件,而不是一个动作,所以它是适当的小黄瓜。

所以现在你可能会想“但是代码重用怎么办??!?!?”,这就是流和lib派上用场的地方。如果您发现自己经常重复使用代码,请将其移动到可以调用以在stepdef中引用该操作的lib,这样您就可以将您的功能文件保存在正确的小黄瓜和stepdef中,并尽可能少地重用代码< / p>

答案 1 :(得分:0)

您更正确的是,Gherkin场景描述了在被测试应用程序中的Arrange,Act和Assert步骤。

如果你有足够的小黄瓜语句,可以在小黄瓜中描述鲍勃叔叔的有限状态机。但是,记住,Gherkin中的每个场景都是从初始状态开始,而不是从位于其上方的场景末尾的状态开始。

换句话说,每个场景都必须独立。

测试步骤的潜在重复性不如描述完整的方案重要。一个原因是测试运行器可能选择性地运行场景,如果未执行前驱场景,则会导致测试失败。其他测试运行器可以并行运行场景,如果允许这样的依赖,也会造成严重破坏。

在几种情况下重复给定步骤是完全可以接受的,也是常见做法。

你的例子会更恰当地说明:

Given the user is interested in some item
When the user adds the item to their cart
Then the cart will include the item

Given the user has added an item to their cart
When the user checks out
Then the user will see a summary of their purchase including the item

Given the user purchases an item
When the user cancels the item
Then the item should be canceled

第三个Given语句可以包括其定义中的步骤,让用户将项目放入购物车并结帐,尽管它也可以简单地从头开始创建发票。这是Gherkin的美丽:实现前提条件 并不重要,验证是该行为会导致预期的结果。

答案 2 :(得分:0)

我不认为你应该重新使用当作为吉文斯的步骤。相反,你应该建立在步骤与之交互以创建你的Givens的功能上。通常,每个步骤都有可能在其功能上构建多个给定步骤。

在某些情况下,您将在每个步骤中执行完全相同的操作。例如登录

Data Source=<your server name>;AttachDbFileName=database path\databaseName.mdf;Integrated Security=True" + ";User Instance=True" + ";Context Connection=False;

为了使这些步骤正常工作,我们介绍一个帮助方法

When "I login" do
  visit login_path
  fill_in id
  fill_in password
  ...
end

Given "I have logged in" do
  visit login_path
  fill_in
  ...
end

现在我们可以在几乎没有任何费用的情况下获得更好的语法优势,我们可以在此基础上进行其他有用的步骤

e.g。

module LoginStepHelper
  def login(as: )
     visit ...
  end
end
World LoginStepHelper

When "I login" do
  login as: @i
end

Given "I have logged in" do
  login as: @i
end

在大多数情况下,您有机会为您的Give做一些不同的事情。让我们说我们想要注册一个用户。对于何时我们将通过某种UI与表单进行交互。但是对于Given,我们可以绕过UI。在我们的实施中,我们将有

Given Fred is logged in
Given I am logged in as an admin
...

虽然我们的可能是

When I register
  visit registration_path
  fill_in ...
  ...
  submit
end

我们的Given有两种创建注册的方法

  1. 使用适当的params hash直接调用用于创建注册的服务
  2. 致电工厂/夹具创建者直接将注册记录写入数据库。
  3. 在这两个中,第一个远远优越。

    现在,您的语法越来越好,运行时成本也大幅降低。当您想要进行涉及大量现有功能的复杂交互时,这一点变得尤为重要。注册客户在电子商务网站上重新订购。

答案 3 :(得分:0)

如果您使用的是Javascript,我已经创建了一个名为reuse-cucumber-scenarios的程序包,用于执行以下操作来调用方案:

Given the scenario "@scenario_tag"

Given the scenario "@scenario_tag" with parameters
"""
{
  "1": ["step1_param1", "step1_param2"],
  "2": ["step2_param1", "step2_param2", "step2_param3"],
  "3": ["step3_param1", "step3_param2", "step3_param3"],
}
"""

或创建黄瓜变量...

Given the variable "$variable_name" is equal to
"""
#JSON object
"""

或创建方案功能并通过执行...调用它们。

Given the scenario "@$scenario_function_tag" where variable "$variable_name" is "value_to_replace"

更多...