以下三个示例BDD语句应该有助于解释我的问题:
Scenario: User logs in
Given I am on the login screen
When I enter the valid username "myUsername"
And I enter the valid password "myPassword"
And I press the login button
Then I should see the login successful page
Scenario: User buys a product
Given I am logged into the system using username "myUsername" and "myPassword"
When I purchase the product "myProduct"
Then I should have "myProduct" in the product inventory
VS
Scenario: User buys a product
Given I am on the login screen
And I enter the valid username "myUsername"
And I enter the valid password "myPassword"
And I press the login button
When I purchase the product "myProduct"
Then I should have "myProduct" in the product inventory
所以上面的场景1很好,但最好是在声明2和3之外。声明2读得很好,更简洁。但我的步骤定义为 “鉴于我使用用户名”myUsername“和”myPassword“登录系统 将需要重复调用页面对象(或等效的),方案1调用...似乎更多的开发工作。
所以真的只是想知道是否有人知道哪种是最佳做法。我在网上搜索过,发现了以下文件: http://docs.behat.org/guides/1.gherkin.html
这个建议方案2是最好的,但随后写道:“验证用户(无交互建议的例外。”先前发生的事情“可以”)“哪种情况适合于方案3。
干杯,
查理
答案 0 :(得分:12)
以下是我对您编写的方案的评论。
Scenario: User logs in
Given I am on the login screen
When I enter the valid username "myUsername"
And I enter the valid password "myPassword"
And I press the login button
Then I should see the login successful page
优点:您正确使用Given,When和Then语句。在这种情况下,Given设置系统的初始状态,When表示用户将采取的操作,然后详细说明用于验证系统行为的断言。
缺点:虽然您所写的内容可行,但您遇到的问题是此测试很脆弱。如果您的公司要求在登录期间也必须指定与时间相关的安全令牌(例如),则必须添加另一个步骤来输入此附加字段。但是,如果您将此步骤重写为声明性的,例如
Given I am on the login screen
When I submit valid log-in criteria
Then I should see the login successful page
然后,如果登录过程发生了变化,您只需要更改代码,方案就会保持不变。
Scenario: User buys a product
Given I am logged into the system using username "myUsername" and "myPassword"
When I purchase the product "myProduct"
Then I should have "myProduct" in the product inventory
优点:与上述相同。
缺点:同样,测试很脆弱,因为它是必要的,即您指定了确切的登录凭据和特定产品。我将其重写为:
Given I am logged into the system
When I purchase a product
Then I should have that product in the product inventory
您可以保存ScenarioContext.Current中“何时”步骤中指定的产品。然后,您可以在“Then”步骤中重复使用此值,以断言它存在于产品库存中。
Scenario: User buys a product
Given I am on the login screen
And I enter the valid username "myUsername"
And I enter the valid password "myPassword"
And I press the login button
When I purchase the product "myProduct"
Then I should have "myProduct" in the product inventory
缺点:由于您错误地使用Given语句,这是您最糟糕的情况。应该使用Given语句来定义测试的初始系统状态,因此在这种情况下“给定我在登录屏幕上”是正确的用法,但是“给定我输入有效的用户名”myUsername“”是不正确的用法。它是不正确的,因为它表示用户操作,因此它应该由When覆盖。是的,您可以使用Given执行与When相同的编程步骤,但它不能正确执行!
我将此方案更改为我在方案2中建议的版本。
答案 1 :(得分:1)
首先,Gherkin绝对没有任何内容可以阻止您以任何顺序编写规范,甚至可以生成复合规范,例如
Given ...
When...
Then ...
When ...
Then ...
Given ...
When ...
Then ...
那么你为什么要这样做?
首先,让我们考虑您的方案的第四个变体
Scenario: User logs in and buys a product
Given I am on the login screen
When I enter the valid username "myUsername"
And I enter the valid password "myPassword"
And I press the login button
Then I should see the login successful page
When I purchase the product "myProduct"
Then I should have "myProduct" in the product inventory
这当然只是1和2的复合词。您可能已经写过这个,因为您已经完成了登录测试,并希望快速编写和测试购买产品。您已经拥有方案一中Binding
的代码,现在只需编写方案二的绑定。您可能会认为这是最简单的实用更改,您将在以后重构它。这没有什么不对,运行测试可能会更快,但也不完全理想。
现在想象一下,由于您的商店的性质,您已经编写了许多测试来测试不同的购买流程。我们可能正在测试当您将相同的商品再次添加到购物篮中时会发生什么,或者如果您尝试购买缺货商品,或者如果您想要特殊交货,则可以测试不同的结账体验。事实上,您的商店非常成功,您需要在网络上真正安全并更改您的登录过程。不幸的是,你现在拥有这三行
Given I am on the login screen
When I enter the valid username "myUsername"
And I enter the valid password "myPassword"
在整个场景中重复。如果我们用一些错误的代码意外破坏了我们的登录过程,突然我们所有的测试都失败了。你会看到一堵红色的墙,无法真正缩小从哪里开始看问题。因为我们在运行场景之前依赖于登录,所以我们无法将登录与购买隔离开来。
这确实是Given
和When
之间的区别。 When
表示我们正在执行一个进程,Given
是一种直接影响运行时环境的方法,因此我们只需拥有正确的状态。这基本上是
//Given
isLoggedIn = true
//When
if CheckValidPasswordForUser(user, password)
isLoggedIn = true
Given
无法失败。
所以回到原来的问题,
您可以重新使用Given
作为When
s吗?是的,但从长远来看,它会让您感到困惑。
但是如果你问你可以重新使用When
作为Given
s?那么我肯定会建议你不要这样做。这将隐藏可能破坏的东西正在测试的事实。
最后还有另外一件事要考虑,那就是你的规范域。 Dan North在这篇Whose Domain is it anyway?上有一篇非常好的文章,但是这里适用于你的例子的一般要点是,当你在看产品购买时,你可以简单地写一下
Given I am logged in as a customer
或
Given I am logged in as an administrator
因为用户名和密码部分是使用登录而不是产品,这样当您更改登录过程以使用其他内容时,您就不会重写所有方案。