您可以将所有步骤定义放在一个文件中,也可以放在多个文件中。当您开始您的项目时,您的所有步骤定义可能都在一个文件中。随着项目的增长,您应该将步骤定义拆分为不同文件中具有意义的组。这将使您的项目更合乎逻辑,更容易维护。
Cucumber 如何找到您的功能和步骤定义
请注意,无论采用哪种目录结构,Cucumber 在运行测试时实际上会扁平化 features/
目录树。这意味着在运行 Cucumber 的目录中,所有以 .java
.kt
.js
.rb
.go
结尾的文件都被视为步骤定义。在同一个目录中,Cucumber 将搜索与该步骤定义相对应的 Feature
。这要么是默认情况,要么是使用 relevantrelevantrelevant-r
relevant 选项指定的 location。
对步骤定义进行分组
从技术上讲,您如何命名步骤定义文件或在哪个文件中放置步骤定义并不重要。您可以有一个包含所有步骤定义的巨型文件。但是,随着项目的增长,该文件可能会变得杂乱无章,难以维护。相反,我们建议为每个域概念创建一个单独的 *_steps.rb
StepDefinitions.java
StepDefinitions.kt
*_steps.js
*_steps.go
文件。
一个好的经验法则是为每个主要的 模型/数据库表。域对象。域对象。域对象。域对象。创建一个文件。
例如,在 Curriculum Vitae 应用程序中,我们可能有
employee_steps.rb
education_steps.rb
experience_steps.rb
authentication_steps.rb
EmployeeStepDefinitions.java
EducationStepDefinitions.java
ExperienceStepDefinitions.java
AuthenticationStepDefinitions.java
EmployeeStepDefinitions.kt
EducationStepDefinitions.kt
ExperienceStepDefinitions.kt
AuthenticationStepDefinitions.kt
employee_steps.js
education_steps.js
experience_steps.js
authentication_steps.js
employee_steps.go
education_steps.go
experience_steps.go
authentication_steps.go
前三个文件将定义与创建、读取、更新和删除各种 模型。对象类型。对象类型。对象类型。相关的 Given
、When
和 Then
步骤定义。最后一个文件将定义与登录和注销相关的步骤定义,以及特定用户在系统中允许执行的不同操作。
如果您遵循这种模式,您也可以避免 功能耦合的步骤定义 反模式。
当然,如何对步骤定义进行分组真正取决于您和您的团队。它们应该以对您的项目有意义的方式进行分组。
编写步骤定义
不要为您的场景中不存在的步骤编写步骤定义。这些最终可能会成为需要清理的未用 垃圾。只实现您真正需要的步骤定义。随着项目的增长,您可以随时重构您的代码。
避免重复
避免编写类似的步骤定义,因为它们会导致混乱。虽然记录您的步骤有帮助,但利用 辅助方法 对它们进行抽象可以带来奇迹。
例如,以下步骤
Given I go to the home page
Given I check the about page of the website
Given I get the contact details
如果所有这些步骤都打开了它们各自的网页,您可能正在编写冗余步骤。虽然这些步骤的底层代码可能不同,但它们的行为本质上是相同的,即打开主页、关于页或联系页。
因此,您可以使用抽象的辅助方法将它们减少为一个步骤
Given I go to the {} page
以及以下步骤定义
@Given("I go to the {string} page")
public void i_want_to_open_page(String webpage) {
webpageFactory.openPage(webpage);
}
Given("I go to the {string} page", function (webpage) {
webpageFactory.openPage(webpage)
}
Given 'I go to the {string} page' do |page|
open_web_page page
end
@Given("I go to the {string} page")
fun `I want to open page`(webpage: String) {
webpageFactory.openPage(webpage)
}
s.Step(`^I go to the "([^"]*)" page$`, goToPage)
func goToPage(webpage string) error {
return webpageFactory.Open(webpage)
}
您的步骤定义是实际代码的粘合剂(在本例中,是用于决定打开哪个页面的工厂方法)。它们还可以通过从一个步骤定义调用多个可重用辅助方法来隐藏实现细节。
这在很多方面都有帮助
- 提高可维护性。
- 使用可重用步骤提高可扩展性。
- 更易于理解的测试。
您可以以相同的方式处理其他行为,例如验证网页、单击按钮等。
我们建议看一下 工厂设计模式。我们建议看一下 工厂设计模式。我们建议看一下 工厂设计模式。 此外,使用 数据表 为步骤提供输入有助于提高可维护性和可理解性。
辅助方法
请始终牢记,Cucumber 是围绕编程语言的 DSL 包装器,您可以在步骤定义文件中使用该语言的完整表达能力(但在功能文件中则不行)。另一方面,不要忘记,每个在步骤定义文件中作为步骤调用的内容都将首先由 Gherkin 解析,因此必须符合功能文件中使用的相同语法。
实际上,建议将步骤定义重构为辅助方法,以提高模块化和可重用性。该方法可以与步骤定义位于同一个 .java
.kt
.js
.rb
.go
文件中。
这使您的项目更易于理解,以便日后加入您项目的人员更容易维护您的项目。