如何提高SpecFlow / Gherkin步骤之间的可重用性?

时间:2012-07-10 16:48:55

标签: cucumber bdd specflow acceptance-testing gherkin

我认为我完全理解SpecFlow背后的概念和想法,但即使在阅读Secret Ninja Cucumber ScrollsThe Cucumber Book并浏览各种论坛后,我仍然不确定可重用性的路径。< / p>

我们的方案已经符合各种指南

  • 自我解释
  • 必须具有可理解的目的(使其与其他方案不同的是什么)
  • 很独特
  • 代表垂直功能切片
  • 使用无所不在的语言
  • 从利益相关者的角度撰写
  • 关于业务功能,而不是关于软件设计
  • 由Epics分组
  • 不是测试脚本
  • 让其他人阅读它们以查看方案是否正确
  • 不引用UI元素
  • 代表关键示例
  • 非技术
  • 精确且可测试
  • 尽可能重复
  • '给定'代表州,而非行动
  • '何时'代表行动
  • '然后'应该代表一个明显的变化,而不是一些内部事件

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

  • 使用无所不在的语言
  • 不引用UI元素
  • 不应合并
  • 应该可重复使用并且可以全局使用所有功能
  • 不应与特定功能相关联
  • 按实体,实体组或域概念分组
  • 不要创建在步骤定义文件中重用逻辑的步骤
  • 彻底思考步骤所属的步骤文件
  • 不要在阶段之间重复使用步骤
  • 必须避免步骤中的文字字符串,但如果需要,请使用单引号
  • 永远不要将多个[Given],[When]或[Then]属性应用于该步骤 方法
  • 根据他们所代表的阶段订购步骤
  • 如果对于该场景不重要,那么更重要的是不要提及

但即使我们使用正则表达式占位符,我们仍然会得到相同步骤的大量变体。特别是如果某些事情不重要,你就不应该提到这些变化的规则。是的,在内部这些步骤重复使用,但不在场景中。

例如考虑以下场景:

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

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

2 个答案:

答案 0 :(得分: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

当然这是一种可以滥用的工具,但在某些情况下它可以提供帮助。

答案 1 :(得分:0)

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

在我们的SpecFlow测试中看起来是常见的浏览器操作在基类中:

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

每个方法都可以有一个或多个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")