我正在尝试为大型应用程序创建功能和步骤定义的可扩展结构,我的第一个尝试是尝试将 step_definition 文件链接到功能,以便我可以对不同的步骤定义使用相同的步骤模式。
我展示了我当前的示例:
我的文件夹结构:
/features/sample.feature
/features/example.feature
/features/step_definitions/sample_steps.js
/features/step_definitions/example_steps.js
/features/step_definitions/common/common_steps.js
在我的sample.feature
我有:
Scenario: Launching Cucumber
Given I have some step definitions
When I check some step definition with parameter "any"
Then I should see all green "sample"
在我的example.feature
我有:
Scenario: Launching Cucumber
Given I have some step definitions
When I check some step definition with parameter "any"
Then I should see all green "example"
Given
和When
步骤在/common/common_steps.js
文件中定义并且工作正常。
Then
步骤被定义为sample_steps.js
和example_steps.js
但不同。
在我的 sample_steps.js 我有:
Then('I should see all green {stringInDoubleQuotes}', (arg) => {
if (arg !== 'sample') {
throw 'I should see all green when the argument is "sample"';
}
return;
});
最后,在我的 example_steps.js 中,我有:
Then('I should see all green {stringInDoubleQuotes}', (arg) => {
if (arg !== 'example') {
throw 'I should see all green when the argument is "example"';
}
return;
});
我的主要目标是在这里全部变绿,但是当然,它不起作用,我得到了这个明显的错误:
Multiple step definitions match:
I should see all green {stringInDoubleQuotes} - features\step_definitions\example_steps.js:6
I should see all green {stringInDoubleQuotes} - features\step_definitions\sample_steps.js:6
我知道在 cucumber-jvm 中我们可以指定一个glue
属性来链接功能和 step_definitions,这正是我正在寻找的,但是在 cucumber-js 中。 Java 中的示例:
@RunWith(Cucumber.class)
@Cucumber.Options( glue = { "com.app.stepdefinitions.common", "com.app.stepdefinitions.sample" } )
public class SampleFeature{
}
@RunWith(Cucumber.class)
@Cucumber.Options( glue = { "com.app.stepdefinitions.common", "com.app.stepdefinitions.example" } )
public class ExampleFeature{
}
如何使用 cucumber-js 实现与 cucumbr-jvm 相同的效果?
我正在尝试为大型应用程序创建功能和步骤定义的可扩展结构,我的第一个尝试是尝试将 step_definition 文件链接到功能,以便我可以对不同的步骤定义使用相同的步骤模式。
很有意思。 cucumber-js 没有像您提供的 cucumber-java 示例那样内置任何内容。 我喜欢这种类型的想法,就是将这种逻辑切换到你的世界设置或实例中。 无论哪种方式,您最终都只有一个步骤定义。 您可以在定义支持代码时在多个世界定义之间切换,或者拥有一个基于上下文公开不同方法的世界实例。 我们目前不将当前场景的文件公开给正在运行的步骤,但您可以使用标签来确定您的上下文。
我们实际上对此有同样的需求。 我们正在使用nightwatch-cucumber来运行 selenium 测试,我们目前唯一的解决方案是为每个步骤添加一个前缀:
Given [comp1] I click on "Open dialog"
对比
Given [comp2] I click on "Open dialog"
这有助于我们避免模棱两可的步骤定义,但会导致真正不可读的功能文件。
我尝试修改 cucumber.js 源代码,但没有找到添加对此功能支持的好提示。
这可以通过一些钩子或替代世界来实现吗?
@leipert您设想的用户界面是什么? 我相信这个逻辑应该存在于世界中或支持多个世界对象。 然后步骤定义只处理解析小黄瓜匹配并将它们传递给适当的世界函数。 我们可以添加一个 CLI 选项来选择要使用的世界对象。
目前,如果您想拥有多个世界/步骤定义,您可以通过将代码放在单独的文件夹中并且每次运行只需要其中一个来实现这一点(使用 --require CLI 选项)。
好吧,“黄瓜书”特别不鼓励这种设计步骤的方式。 步骤是通过设计在场景之间共享的,尽管使用它的功能,同一个句子应该具有一致的含义。 一旦你介绍了步骤的范围,就很容易制造语言陷阱。
到目前为止,只有标签接近你在 cucuber.js 中的目的。 但是只有钩子可以声明它们是特定于标签的。 如果您确定这对您的员工来说是正确的方式,您可能会发明一种 DSL,可能很简单,例如 [feature name] in step 模式。
谢谢, @pinxue 。 非常有用的回应。 但是,我无法理解:
好吧,“黄瓜书”特别不鼓励这种设计步骤的方式。
相同的动作短语在不同的上下文中可能具有不同的含义。 但没关系。 很高兴知道我的选择,实际上,我们已经在内部 DSL 上实现它,
非常感谢。
感谢您的回答@pinxue和@robsonrosa。
这是我对范围步骤定义的推理:
我看到以下方法可以为我们解决问题:
glue
cucumber.js
话虽如此,如果 cucumber.js 的维护者认为范围内的步骤定义超出了该项目的范围(双关语),我们可能会选择 3.。
@robsonrosa ,一旦您有了解决方案,我就会对您的解决方案感兴趣。
绝对需要 IMO 范围界定。 随着您的应用程序的增长,功能的数量会增加,您最终会在不同的上下文中得到相互冲突的描述。
在我的公司,我们的产品有数百个功能,QA 有 100k 范围内的测试用例。
如果我们使用cucumber
我们肯定会遇到这个问题。
是的,我认为您应该考虑上下文而不是范围。
您可以在默认上下文(或无上下文)中拥有大部分(如果不是全部)步骤定义,但应该有一种方法可以在不需要自定义 DSL 的情况下指定上下文。
应该由 BA 和 QA 编写这些测试,并且任何自定义 DSL 都必然会造成混乱和阻力。
Feature/Scenario 已经根据定义提供了上下文,这就是 Gherkin 语法有缩进的原因。
添加标签和自定义 DSL 是实现限制的解决方法(即 hack,IMO),而不是解决方案。
也许您可以在考虑https://github.com/cucumber/cucumber-js/issues/745 的同时考虑这一点?
如何从defineStep
扩展Scenario
$ 并将{Given, When, Then}
传递到回调中?
IE:
import {defineSupportCode} from 'cucumber'
defineSupportCode(({ Scenario, Given, When, Then }) => {
Given(...)
When(...)
Then(...)
Scenario('<match scenario description>', ({ Given, When, Then}) => {
Given('<take precedent of non-contexted>', ...)
...
})
})
我从http://fitnesse.org/学习 BDD,因此我对 BDD 的看法可能与黄瓜社区不同。
寻呼@richardlawrence
这是黄瓜特别固执己见的一个领域。 它建立在团队应该发展一种无处不在的语言的信念之上,其中单词和短语在应用程序的上下文中意味着完全一样的东西并且被一致地使用。 保持 step defs global 会保持积极的压力,以避免模棱两可。
在应用程序具有多个不同的有界上下文(在 DDD 术语中)的极少数情况下,您只需按照划分应用程序以反映该边界的相同线划分您的 Cucumber 套件,并且步骤定义在每个有界上下文中都是全局的。
一篇关于使用 Cucumber 和创建边界的文章。 它实现了此页面上的一些想法,但没有提供任何出色的解决方案,因为@richardlawrence提到您不能将 Cucumber 配置为专注于一个特定的类以进行步骤定义。 http://confessionsofanagilecoach.blogspot.com/2017/05/teaching-cucumbers-about-boundaries.html
正如@leipert所说,全局变量很糟糕。 我认为我们这些 CucumberJVM 世界中的人只了解了一半。 Cucumber(非 JVM)使用 tidy World 概念,它是Scenario 期间的全局内存空间。 场景执行后,它被销毁。 这感觉是一个很好的解决方案。 但是...我在 CucumberJVM 中没有看到这种模式的良好实现。 因此,如果 Cucumber 强制我们为步骤定义使用平面/全局命名空间,并且 CucumberJVM 有一个清晰的设计模式来实现 World 模式,那么我会更开心一点。 至此,CucumberJVM + World 模式 == 过于复杂的解决方案。 到目前为止,我所看到的一切都比简单地让我控制哪些步骤功能与哪个功能文件一起使用要复杂得多。 到目前为止,我所看到的替代方案对于所有的努力/复杂性来说都没有什么更有价值的。 其他类型的 Cucumber 有更好的 World 解决方案。
最终,即使使用 World 模式,我仍然不满意,因为我知道从功能文件到步骤时会丢失信息。 如果我付出很大的努力:把我的功能文件放在一个好的组织中,创建好的功能文件名,以一种聪明的方式声明我的功能,以一种聪明的方式命名我的场景——所有的上下文都被扔出窗外,我被迫使用全局步骤定义命名空间。
我只能考虑将关系排除在系统验证之外,并简单地在测试路径上添加通配符,并使它们工作,即使它需要修改一些开源框架。 随着我们项目的发展,可能会试一试。
我理解你的目标,但我不会推荐它。
我还建议使用明确的 .feature 文件,使用背景语句或附加的Given步骤来明确说明。
或者,您可以制作两个不同的配置文件。
一个用于示例,另一个用于示例。
然后你可以指向不同的步骤文件夹。
@robsonrosa @leipert我同意你的意见
原帖后将近两年...
你在这方面有什么进展吗? 任何解决方法?
@cristianmercado19对不起,不。 我不再使用黄瓜 js。
Ups...我喜欢编写与步骤实现完全隔离的功能文件的方式。
我试图用_mocha_实现同样的目标,但我不满意。
如果您有任何其他符合我目标的选择,非常乐意试一试。
感谢您的帮助@leipert 。
该线程已被自动锁定,因为它关闭后没有任何最近的活动。 请为相关错误打开一个新问题。
最有用的评论
绝对需要 IMO 范围界定。 随着您的应用程序的增长,功能的数量会增加,您最终会在不同的上下文中得到相互冲突的描述。
在我的公司,我们的产品有数百个功能,QA 有 100k 范围内的测试用例。
如果我们使用
cucumber
我们肯定会遇到这个问题。是的,我认为您应该考虑上下文而不是范围。
您可以在默认上下文(或无上下文)中拥有大部分(如果不是全部)步骤定义,但应该有一种方法可以在不需要自定义 DSL 的情况下指定上下文。
应该由 BA 和 QA 编写这些测试,并且任何自定义 DSL 都必然会造成混乱和阻力。
Feature/Scenario 已经根据定义提供了上下文,这就是 Gherkin 语法有缩进的原因。
添加标签和自定义 DSL 是实现限制的解决方法(即 hack,IMO),而不是解决方案。
也许您可以在考虑https://github.com/cucumber/cucumber-js/issues/745 的同时考虑这一点?
如何从
defineStep
扩展Scenario
$ 并将{Given, When, Then}
传递到回调中?IE: