是的,当现实世界的场景需要它时,在 Gherkin 场景中不止一个When
/循环是合适的。Then
SaxonMatt 的回答提出了一个很好的观点,即最好用利益相关者的语言而不是 UI 操作的语言编写场景,这样做通常会缩短场景的长度,但这错过了问题的确切要点。让我们抓住公牛的角。
Gherkin 是为验收测试而设计的:测试利益相关者级别的需求是否已完全实现,即软件是否确实为利益相关者提供了价值。有时提供价值需要不止一个行动-响应周期。考虑以下场景:
Scenario: Guest buys a product
# This scenario starts with the user not logged in, which doesn't require a step
Given there is a product named "Elliptical Juicer"
When I go to the product page for "Elliptical Juicer"
And I add the product to my shopping cart
Then I should see 1 product in my shopping cart
When I request to check out
Then I should see the account creation form
When I create an account
Then I should see the checkout form with 1 product, "Elliptical Juicer"
When I check out
Then I should see the checkout success page with 1 product, "Elliptical Juicer"
And I should receive a checkout confirmation email with 1 product, "Elliptical Juicer"
(请注意,当我在一个场景中有多个When
/Then
循环时,我喜欢用空行分隔它们,以便它们脱颖而出。)
When
最好使用多个/Then
循环编写此方案有几个原因:
在用户结帐之前,他们应该在他们的购物车中看到一个产品(仅作为站点标题中的一个数字,因此该步骤没有提及产品名称)。在场景结束时无法测试此要求。(好吧,测试可以在用户将产品添加到他们的购物车后立即收集信息,并在场景结束时断言预期的计数,但这将毫无意义地偷偷摸摸和混淆。)相反,在自然状态下断言正确的计数放置在场景中,只要它对用户可见。
类似地,Then I should see the account creation form
并且Then I should see the checkout form with 1 product, "Elliptical Juicer"
可以在场景中自然测试它们的点测试重要需求。
假设我们不关心用户在这个过程中看到了什么,只关心他们是否带着他们的产品到达场景的结尾。然后我们可以省略中间Then
步骤:
Given there is a product named "Elliptical Juicer"
When I go to the product page for "Elliptical Juicer"
And I add the product to my shopping cart
And I request to check out
And I create an account
And I check out
Then I should see the checkout success page with 1 product, "Elliptical Juicer"
And I should receive a checkout confirmation email with 1 product, "Elliptical Juicer"
And I create an account
出乎意料,不是吗?它要求读者推断访客用户在结账时被要求创建一个帐户。更明确地说,就像我给出的场景的第一个版本一样。
假设上述问题都没有说服我们,并且我们为整个场景中的每个点编写了一个单独的 Gherkin 场景,我们需要断言需求已经得到满足:
Scenario: Guest adds a product to their shopping cart
Given there is a product named "Elliptical Juicer"
When I go to the product page for "Elliptical Juicer"
And I add the product to my shopping cart
Then I should see 1 product in my shopping cart
Scenario: Guest with a product in their shopping cart attempts to check out
Given I have a product in my shopping cart
When I request to check out
Then I should see the account creation form
Scenario: Guest creates an account
Given I have a product named "Elliptical Juicer" in my shopping cart
And I am on the account creation form
When I create an account
Then I should see the checkout form with 1 product, "Elliptical Juicer"
Scenario: Newly registered user checks out
Given I am a user
And I have a product named "Elliptical Juicer" in my shopping cart
And I am on the checkout form
When I check out
Then I should see the checkout success page with 1 product, "Elliptical Juicer"
And I should receive a checkout confirmation email with 1 product, "Elliptical Juicer"
那是糟糕的!首先,没有一个场景是利益相关者认为的场景。其次,当中间状态之一改变时,两个步骤将不得不改变:断言中间状态的Given
步骤和为下一个场景设置中间状态的步骤。这些Given
步骤中的每一个都是设置错误状态的机会,即产生集成错误。这组场景作为集成测试套件的价值远低于单一场景。您可能几乎已经编写了一系列单元测试。
确实,端到端编写每个场景可能会导致一些重复。正如您在单元测试中比在常规代码中更能容忍重复一样,在 Gherkin 场景中比在单元测试中更能容忍重复。不要在可理解性上妥协。分解场景并Given
仅在关键点使用 s(例如在上面的示例中创建产品),并且知道您正在稀释场景的集成测试能力。
另外,请记住,验收测试应该只是自动化测试套件的一部分。只编写足够的验收测试来覆盖关键场景,并用单元测试覆盖细节。通常情况下,验收测试重复的解决方案是用单元测试替换一个。