7

我想我彻底理解了 SpecFlow 背后的概念和想法,但是即使在阅读了Secret Ninja Cucumber ScrollsThe Cucumber Book并浏览了各种论坛之后,我仍然不确定通往可重用性的道路。

我们的场景已经符合各种准则

  • 不言自明
  • 必须有一个可以理解的目的(是什么使它与其他场景不同)
  • 是独一无二的
  • 表示垂直功能切片
  • 使用无处不在的语言
  • 从利益相关者的角度撰写
  • 关于业务功能,而不是软件设计
  • 按史诗分组
  • 不是测试脚本
  • 让其他人阅读它们以查看场景是否正确
  • 不涉及 UI 元素
  • 代表关键示例
  • 非技术
  • 精确且可测试
  • 尽可能重复
  • “给定”代表状态,而不是动作
  • 'When' 代表动作
  • “那么”应该代表一个可见的变化,而不是一些内部事件

我们的步骤必须遵守以下准则(一些特定于 SpecFlow):

  • 使用无处不在的语言
  • 不涉及 UI 元素
  • 不应该合并
  • 应该是可重用的,并且在所有功能上都是全局的
  • 不应链接到特定功能
  • 按实体、实体组或领域概念分组
  • 不要创建步骤以重用步骤定义文件中的逻辑
  • 仔细考虑一个步骤属于哪个步骤文件
  • 不要在阶段之间重用步骤
  • 必须避免在步骤中使用文字字符串,但如果需要,请使用单引号
  • 切勿将多个 [Given]、[When] 或 [Then] 属性应用于 step 方法
  • 根据它们所代表的阶段对步骤进行排序
  • 如果对场景不重要,很重要的就别提了

但是即使我们使用正则表达式占位符,我们仍然会得到相同步骤的许多变体。尤其是如果某件事不重要,则不应提及它的规则会导致这些变化。是的,在内部,这些步骤做了很多重用,但不是在场景中。

例如考虑以下场景:

Feature: Signing where both persons are physically available

@Smoke
Scenario: Show remaining time to sign based on previous signature
  Given a draft proposal
  And the first signature has been set
  When I try to set the second signature
  Then the remaining time to sign should be shown

@Smoke
Scenario: Re-signing of the first proposal
  Given a signature that has not been set within the configured time
  And the first signature has just been re-signed
  When I try to set the second signature
  Then the remaining time should start over

将两个“给定”步骤合二为一并失去一些可重用性会更好吗?

其他一些例子:

Feature: Conditionally show signatures to be signed

@Smoke
Scenario: Show the correct signature for a proposal with a night shift
  Given I have a proposal for the day shift
  When I change it to the night shift
  Then I should only be able to sign for the night shift

@Smoke
Scenario: Show additional signature when extending the shift
  Given I have a suspended proposal for the night shift
  When I extend the period to the day shift
  Then I should confirm extening the period over the shift

我在这里错过了一个基本概念吗?

4

2 回答 2

12

这不是答案,而是一些提示:

  • 您可以将多个 Given/When/Then 属性放在同一个方法上。如果参数相同并且仅在措辞上有所不同,这可能很有用
  • 在许多项目中,我们使用驱动程序/页面对象模式,因此步骤定义通常很短(2-3 行),因此我们不太关心它们的数量
  • 我喜欢你的场景,我不会改变它们。另一方面,尽量关注可读性而不是可重用性。如果你的语言是一致的,那么可重用性就会到来。
  • 为了增加可重用性,特别是当您正在谈论的实体有很多“变化”时,您可以考虑使用step argument transformations。这是一个例子:

您需要一个类来表示带有装饰的测试中的许可证:

class PermitDescription{
  bool suspended;
  bool draft;
}

创建转换器方法:

[StepArgumentTransformation("permit")]
public PermitDescription CreateSimple(){
  return new PermitDescription();
}
[StepArgumentTransformation("draft permit")]
public PermitDescription CreateDraft(){
  return new PermitDescription() { draft = true; }
}
[StepArgumentTransformation("suspended permit")]
public PermitDescription CreateSuspended(){
  return new PermitDescription() { suspended = true; }
}

您现在可以拥有需要许可的更灵活的步骤定义:

[Given(@"I have a (.*) for the day shift")]
public void Something(PermitDescription p)
{ ... }

匹配:

Given I have a permit for the day shift
Given I have a draft permit for the day shift
Given I have a suspended permit for the day shift

当然,这是一个也可能被滥用的工具,但在某些情况下它会有所帮助。

于 2012-07-13T07:54:47.087 回答
0

补充来自@gaspar-nagy 的答案它遵循 C 编程中的类设计模式。在任何地方,一组公共类共享公共属性/方法,这些属性/方法可以重构为基类。

在我们的 SpecFlow 测试中,常见的浏览器操作位于基类中:

Login()
Logout()
NavigateToUrl(string url)
UserHasPermission(string permission)
WaitForElementToAppearById(string id)
WaitForElementToAppearByClass(string class)

并且这些方法中的每一个都可以具有 1 个或多个 Given/When/Then 属性,例如 @gasper-nagy 所述。

另一种被证明是无价的技术是在 .features 和它们各自的 C# 步骤文件之间共享变量是使用 ScenarioContext。

例如,每当Login()调用以启动基于浏览器的测试时,我们都会这样做:
ScenarioContext.Current.Set<IWebDriver>(driver, "driver")

然后在其他任何需要驱动程序的地方,可以通过以下方式获得它:
var driver = ScenarioContext.Current.Get<IWebDriver>("driver")

这使得步骤可重用,例如用于验证的用户输入测试,您可能决定像这样传递正在验证的元素: ScenarioContext.Current.Set<IWebElement>(element, "validation-element")

于 2017-02-20T18:45:12.453 回答