Cucumber-js: 结果缺少场景和标签

创建于 2017-09-05  ·  37评论  ·  资料来源: cucumber/cucumber-js

有什么办法可以在新版本v3中访问scenarioResult.scenario.tags? 是否可以以某种方式覆盖测试用例完成事件以传递旧模型场景结果? 谢谢

最有用的评论

FWIW,cucumber-ruby 有两个扩展点,我认为它们满足“简单的事情应该很容易,困难的事情应该成为可能”的原则,并且可能是可以帮助这些用例的想法。

首先,我们将RunningTestCase一个实例传递给每个钩子。 这是一个不可变的值对象,包含有关 Gherkin 源(场景/大纲/标签等)的所有信息以及场景的当前结果状态。 不可变意味着我们不必考虑用户可能尝试改变我们的事情的情况,但同样它让他们对当前的游戏状态是透明的。

其次,我们有过滤器。 过滤器允许您在执行测试用例之前对其进行操作。 例如,我们使用过滤器从流中删除与 CLI 上指定的标签模式不匹配的测试用例。 过滤器是高级用户功能。

HTH

所有37条评论

不。 您无法轻松访问测试用例的标签。 没有计划返回到旧的场景结果。 您需要标签的用例是什么?

就我而言,我依赖于标签系统。 为了在余波中得到一些数据。

像这样的东西:

<strong i="7">@SuiteName</strong> <strong i="8">@SuiteSectionName</strong> <- These tags tell the suite
Feature: 

<strong i="9">@TC1563697</strong> <- This tag identifies the testcase in the test management tool <strong i="10">@New</strong>
Scenario: 
    Given  
    When 
    Then 

您可以创建仅针对具有特定标签的场景运行的钩子: https :

我还有几个用例来了解场景标签。 给出以下 sudo 示例(由于我在 1.3.1 中有测试用例,因此有点缺少版本语法,我正在查看最新的 3.0.1):

<strong i="6">@set_video</strong> <strong i="7">@youtube</strong>
Scenario: User should see youtube video

<strong i="8">@set_video</strong> <strong i="9">@vimeo</strong>
Scenario: User should see vimeo video


this.After({tags: @set_video}, function (testCase) {
  let tags = testCase.scenario.tags;

_.forEach(tags, (function (tag) {
 if(tag === '<strong i="10">@youtube</strong>') {
   setVideo('youtube');
 }
if(tag === '<strong i="11">@vimeo</strong>') {
 setVideo('vimeo');
}
});

}

我有一个标签说明钩子应该何时运行,我还有其他标签作为数据使钩子更加动态以适用于其他用例。 否则,我发现自己使用相同的逻辑创建了相同的钩子,并且只更改了我传递给它的数据。 我发现了解标签非常有用,并且是使钩子更灵活的非常强大的工具。

我还可以在这里问我似乎无法在 3.0.1 的 After 钩子中获得结果对象。 我尝试了 testCase、scenarioResult 和方案。 我错过了什么吗?

我们有一个案例,我们将测试用例保存在 TestRail 中,然后在运行之前下载它们并保存为功能文件。

然后在 after 钩子中,我们将详细的测试结果发送到我们的 SQL 数据库。 这些结果包括:

  • 来自 TestRail 的功能 ID - 取自标签(每个功能都自动生成带有功能 ID 的标签)
  • 抛出的异常 - 取自黄瓜 1.x 中的scenario.getException()
  • 该功能标记的所有标签
  • 失败的步骤 - 我们使用stepResult钩子来获取每一步的结果
  • 使用从标签中获取的功能 ID 从 TestRail 获取的一堆其他信息

因此,随着 Cucumber 3.x 的当前更改,我们将永远无法切换,因为它完全破坏了我们的基础架构。

@pawelus我的基础设施做的完全一样。
似乎因为异步执行这些操作不会丢失任何东西(即您的实际测试基础设施不“关心”TestRail 更新),您可以将该代码移动到自定义格式化程序中,并使用来自事件的信息构建和发送报告的协议。

我个人有一个启动黄瓜的包装脚本。
它会在启动 Cucumber 之前下载 TestRail 场景,因此将 TestRail 报告代码从 Cucumber 挂钩移出到包装器脚本中对我来说并不是什么大问题。
黄瓜完成后,脚本读取输出的黄瓜结果 JSON,并从那里编译它需要的所有信息。

听起来您必须以任何一种方式重新排列代码。
我认为将所有前/后操作移动到包装器脚本是一个很好的解决方案,可以恢复我们在 V3 中失去的一些控制。
这仍然有点痛苦,因为我必须序列化重要的上下文信息以丰富输出的结果(因为我的基础结构状态在相关代码运行时被破坏),但它是可行的。

我认为失去知道钩子标签的能力将是一种耻辱。 这是使更多可配置的唯一方法,因为您无法将参数传递给它我添加了额外的标签,然后查看哪些应用于当前场景以调用具有不同输入的函数。

@yaronassa我们通过量角器运行我们的测试,我们不直接启动黄瓜,所以这里还有另一层抽象。

我们会像您一样在 Protractor 启动之前下载功能,但将结果发送到数据库是另一回事。

通过在 Selenium 网格上运行分片和测试以及重新运行失败的功能,在数据库中以正确的顺序获取结果将是一个相当麻烦和复杂的逻辑。 大量的工作来恢复我们在黄瓜 1 和 2 中的功能。

还创建一个自定义格式化程序只是为了获得步骤结果听起来不正确。

嘿,我和你在一起。
我本来希望不受限制地访问黄瓜的当前状态 - 功能、场景和步骤,以及它的整个属性集合和写访问权限(我什至想要访问场景的未来“调用堆栈”,并能够事先操作它)。

鉴于cucumberJS 有意摆脱这种“内部可见性”,我提供了我认为在可预见的未来可行的解决方案。 就我个人而言,我认为会有一段时间像我们这样的修补匠将不得不求助于覆盖 Cucumber 内部的内部方法来保留这种访问权限。
没关系 - 我想我们有十几个人,还有成千上万的临时用户。

如果可能的话,我也会支持场景的名称。 事实上,我正在添加快照功能,我需要知道场景的名称来命名我的快照。

@gd46您可以执行以下操作:

this.After({tags: "<strong i="7">@set_video</strong> and @youtube"}, function () {
  setVideo('youtube');
})

this.After({tags: "<strong i="8">@set_video</strong> and @vimeo"}, function () {
  setVideo('vimeo');
})

除了@set_video标志外,没有任何重复。


@pawelus

然后在 after 钩子中,我们将详细的测试结果发送到我们的 SQL 数据库。

您需要在After挂钩中执行此操作吗? 您可以在测试完成后通过解析 json 格式化程序结果来执行此操作吗? 您可以使用事件协议格式化程序以便在结果发生时继续执行此操作,尽管这需要更多处理。 3.x 更改的一个副产品是解析结果移出支持文件并移至独立进程。 我认为这是更好地分离事物以及理想情况下事物最初的构建方式。


@bnadim

您可以使用attach函数添加屏幕截图,让它们在事件 Potocol / json 格式化程序中输出,然后进行一些后期处理以根据场景名称将它们保存到文件中。 不一样:场景名称不能保证是唯一的,而场景 uri 和行号是唯一的。

@charlierudolph我认为这是满足我需求的可靠替代解决方案。 它还消除了分析当前运行场景的需要。 它只是可能导致定义几种钩子组合,以解释给定函数可以在钩子内处理的不同组合。

因此,例如,我有类似的示例,其中我将当前运行的场景标签根据模式拆分并使用匹配的一部分作为函数的参数。 在这些情况下,所有需要执行的步骤都是相同的,唯一改变的是参数。 因此,这将减少挂钩中的几个设置步骤,因此它可以适用于多种情况。

一个这样的例子:

tags: <strong i="9">@clear_w2OnlyUser</strong>, <strong i="10">@clear_w2OnlyArcotEnableUser</strong>

I split based on <strong i="11">@clear_</strong> and grab the second half as the parameter. tagName coming from the old scenario result of getTags, getName. 

let profileToClear = tagName.split('<strong i="12">@clear_</strong>')[1];

browser.waitForAngularEnabled(false);
browser.get(url);
login();
navigate();
deleteProfile(profileToClear);

请让我知道您对此的看法? 我确实相信您的示例在某些情况下很容易替换。 但在其他需要执行几个额外步骤的情况下,您最终可能会重复所有这些步骤。

我的用例是我为每个场景设置了一个模拟服务器,基于我知道它应该如何表现的标签。 为特定的标记场景添加钩子是非常需要维护的,因为我需要为我支持的每个场景添加一个钩子......

我们还在 Before 和 After 钩子中使用了场景名称,以便记录场景的名称。 这样我们就可以在分析测试结果时看到某个场景何时开始和结束。 此更改破坏了该功能。

我正在使用 Cucumber-js 来驱动 Selenium。 本地和浏览器堆栈

我在钩子中使用测试状态(功能、场景、标签、结果等)来处理许多重要的事情。

  • 对 URL 进行特定于场景的更改
  • 根据当前浏览器配置动态跳过测试
  • 使用特定于场景的 URL 将测试结果记录回 Browserstack
  • 使用 Feature 和 Scenario 名称在 Browserstack 中生成会话名称
  • 解析标签以识别和设置特定于场景的浏览器分辨率

所有这些都封装在应用程序中,以启用并发实例以减少整体运行时间。

为什么这些被丢弃?
他们永远不会回来了吗?

@gd46

正在运行的场景是否涉及那种类型的配置文件? 也许你可以让场景保存什么类型的配置文件正在与世界交互,然后你有一个明确的标签来提示删除保存的配置文件?


@justusromijn

对于模拟服务器,您能否将设置从基于标记的设置移动到使用定义设置内容的步骤? 然后您可以轻松地进行参数化。


@Jordyderuijter

您可以记录场景行和 uri(这实际上是唯一的,可以防止您必须搜索场景名称)。


@leggebroten

对 URL 进行特定于场景的更改

您可以为此使用一个步骤或使用唯一标签

根据当前浏览器配置动态跳过测试

你是如何动态跳过测试的? #912 增加对此的支持

使用特定于场景的 URL 将测试结果记录回 Browserstack

您可以使用行和 uri 代替名称。 如前所述,行和 uri 保证是唯一的,而名称则不是。 我还建议解析 json 格式化程序或事件协议格式化程序格式化程序以获得测试结果并在需要添加任何内容时使用附件。

使用 Feature 和 Scenario 名称在 Browserstack 中生成会话名称

您可以使用行 + URI

解析标签以识别和设置特定于场景的浏览器分辨率

您可以为此使用一个步骤。


从所有这些例子中,我还没有一个用例让我相信我们应该向钩子添加返回标签或名称。 拥有标签和名称似乎使某些事情更容易做,但我认为还有其他方法可以完成它们对我更有意义

@charlierudolph感谢您的回复。 对于模拟服务器,我已经与一些同事进行了快速聊天,并且正在考虑使用共享的“背景”作为解决方案,所以是的,您可以跨越列表中的那个。

@charlierudolph感谢您的回复。

虽然您对使用 Steps 和解析输出的建议可以奏效,但它远不如回调可以访问测试状态的先前版本。

0) 与观察者模式不一致。 回调应该提供他们支持的行为所需的数据

1) 导致极度脆弱。 测试应该是可靠的,否则就不会被信任。 行号和文件名改变。 简单地添加或删除回车符会破坏测试。

2) 使用 Steps 来改变 State 违反了 DRY。 考虑添加标有标签的 A/B 测试的常见情况。 除非您添加命令行扩展以根据它们包含的步骤执行测试,否则测试将需要 BOTH Tag 及其支持的状态更改步骤。

3) 需要开发者做额外的工作。 解析输出以查找 State 是不必要的、乏味的、容易出错的、将测试绑定到输出格式(糟糕的耦合),并且违反了 DRY。

4) 与黄瓜不一致。 添加步骤(测试的语义部分)来改变功能的状态与 Cucumber 隔离测试编写者的意图背道而驰。 如果行为没有改变,测试不应该。

5)它不是声明性的。 标签是关于测试的元数据,使用它们来改变测试将运行的状态在语义上是一致的。 而步骤嵌入在测试中。 您可以通过他们的标签来识别一组测试……而不是他们使用的步骤。

哦,我实际上并没有“跳过”测试,我使用 callback(null, 'pending' ) 来避免运行测试。 新的“跳过”功能是卓越的解决方案。

@charlierudolph ,我在想,另一种解决方案......
在构造 World 对象时,提供对用于测试的 Scenario 对象的引用。

由于 World 可作为所有回调的“this”使用,它将实现与 V2 的完全相同(如果给 AfterAll 回调提供了结果)

@leggebroten

  1. 我从来没有听说过观察者模式是黄瓜的设计目标。
  2. 场景名称也很脆弱,因为单个字符的变化也会改变它。 我同意在采取不相关的操作时文件/行号中断。 我建议在结果报告中使用,而不是在运行测试中使用,因此脆弱的部分不会产生太大的负面影响。
  3. Using Steps to alter State violates DRY我不明白这一点。 标签用于选择特征,步骤用于设置/操作/期望。 这些是不同的目的。 我们对使用带标记钩子的设置使用标记的支持很少,但它不是为了处理复杂性而构建的。
  4. 我只是建议解析格式化程序输出以进行报告。 这不应该参与运行测试。
  5. Adding Steps (a semantic part of the test) to alter the Feature's state is counter to intent of Cucumber of isolating test writer我也不明白这一点。 如果您不能使用步骤来执行操作和设置状态,那么您如何运行测试?
  6. Tags are metadata ABOUT the test, it is semantically consistent to use them to alter the state in which the test will run 。 我不同意这是一致的。 对我来说标签仅用于识别测试。 支持最小的状态更改,但不支持带参数的复杂状态更改。

系统中没有更多的场景对象。 我不认为与 v2 的平价应该是一个目标。 我很高兴这次谈话出现了,我很高兴寻找其他解决方案,但我不想回到我们以前的做法,因为我相信这让用户更多地依赖于 Cucumber 的实现而不是它的界面。

@查理鲁道夫

感谢您抽出时间讨论这个问题。 我非常感谢您为我们提供 Cucumber-js 所做的工作。 但就目前而言,我无法升级到 V3。

我不打算好斗。 我只是担心,这可能会出现在我的回答中。

仅使用先前版本中记录的事件接口,我构建了一个框架,通过允许功能在包含操作系统/版本、浏览器/版本、桌面/移动和优化 A/B 测试。

我不能使用步骤。 太晚了。 必须在测试开始之前确定设备类型、操作系统/版本和浏览器/版本,否则每个场景都将被迫具有“设置操作系统”步骤和“设置浏览器”步骤。 这与 Cucumber 的目标直接冲突。

或者,正如我之前提到的,您可以向 World 构造函数提供场景信息(功能 URI、名称、行和标签)。 这在语义上与 World 对象的意图一致,并且更易于封装和扩展。 这不仅会消除我的大部分事件处理程序,而且因为处理程序的“this”是 World 对象,它是与观察者模式一致的状态。

  1. 我没有说观察者模式是 Cucumber 的设计目标。 仅仅 Hooks 和 Events 是观察者,因此,它们应该被赋予完成工作所需的状态。 此模式允许调用者的实现和事件处理程序之间的分离。

  2. 我不依赖于实际名称。 但由于它们是独一无二的,它们是在 Browserstack 中构建关联的用户有意义的会话名称的方法。

  3. 在 Before 期间访问标签集,允许我构建可重用的构造来改变状态(如设置优化 URL 参数),而无需修改测试(添加步骤)。 这意味着我想要运行的测试(标签)与其设置之间存在 1-1 的相关性。 干燥。

  4. 您已经表达了对开发人员变得依赖于实现的担忧,但是您删除必要的观察者状态的解决方案是让开发人员依赖于其他实现(文件格式)? 与访问 State 属性相比,强制用户执行更乏味、更慢且更容易出错的工作解析文件如何更好?

  5. 显然 Steps 正在设置测试状态。 但是 Cucumber 的设计目标之一是编写步骤的人应该与底层实现隔离。 EG 测试语义行为而不会陷入底层细节。 添加步骤来更改查询参数,并定义设备/浏览器/操作系统,似乎与此目标背道而驰。

  6. 对您而言,标签仅用于识别测试。 但是Cucumber Wiki对标签有很多用途。

  7. 组织和分组
  8. 过滤器(通过命令行运行集)
  9. 相关文档的链接(例如 Optimizely 标志)
  10. 指示特征在过程中的位置

在 Before 回调期间访问标签允许我根据用于驱动测试的浏览器配置确保适当的状态。 使用标签使其具有声明性。 使用 Steps 混淆意图

先前版本中事件处理程序的调用和参数是 WERE 接口。 如果开发人员将他们的代码与泄漏的实现耦合,请将只读“场景”代理传递给事件处理程序。

@charlierudolph感谢您的回复

场景名称也很脆弱,因为单个字符的变化也会改变它。 我同意在采取不相关的操作时文件/行号中断。 我建议在结果报告中使用,而不是在运行测试中使用,因此脆弱的部分不会产生太大的负面影响。

诚然,场景名称也很脆弱,但与通过文件和行引用它们相比,引用场景的方式要脆弱得多。 我们每天都在日志中使用场景名称来分析运行中的失败并查看出了什么问题。 如果日志记录仅显示文件和行号,则会导致追溯场景的开销太大。 除此之外,如果有人在此期间更改了功能文件或将场景移到其他地方,这甚至会变得更加复杂。

如果日志记录仅显示文件和行号,则会导致追溯场景的开销太大。

怎么开销更大? 你知道文件和行号,可以直接去那里。 如果您有场景名称,则必须搜索要带到该文件和行的字符串。

怎么开销更大? 你知道文件和行号,可以直接去那里。 如果您有场景名称,则必须搜索要带到该文件和行的字符串。

就像我说的,如果功能文件在此期间更改并且场景不再位于该行上。 特别是当我查看旧测试运行的日志时(例如 1 周前)。 在这种情况下,我将不得不通过 git 并查看在给定时间该行上的场景。

FWIW,cucumber-ruby 有两个扩展点,我认为它们满足“简单的事情应该很容易,困难的事情应该成为可能”的原则,并且可能是可以帮助这些用例的想法。

首先,我们将RunningTestCase一个实例传递给每个钩子。 这是一个不可变的值对象,包含有关 Gherkin 源(场景/大纲/标签等)的所有信息以及场景的当前结果状态。 不可变意味着我们不必考虑用户可能尝试改变我们的事情的情况,但同样它让他们对当前的游戏状态是透明的。

其次,我们有过滤器。 过滤器允许您在执行测试用例之前对其进行操作。 例如,我们使用过滤器从流中删除与 CLI 上指定的标签模式不匹配的测试用例。 过滤器是高级用户功能。

HTH

我刚刚意识到过滤器链接背后的文档很糟糕! 对不起。 现在没有时间修复它,但这里还有更多示例: http :

@charlierudolph

抱歉,我已经有一段时间没有跟进这次谈话了。 您能否详细说明一下您的声明:

“正在运行的场景是否涉及那种类型的配置文件?也许你可以让场景保存哪种类型的配置文件正在与世界交互,然后你有一个明确的标签,提示删除保存的配置文件?”

我不确定我是否遵循。

而且我知道可能有其他方法可以在没有旧测试结果的情况下获得相同的解决方案。 但从我目前在这次谈话中看到的情况来看,所有替代方案似乎都比它们需要的更复杂。 旧的测试结果有大量关于即将运行的场景的描述性数据,这是拥有“参数化”钩子的唯一方法。 从我所看到和尝试的情况来看,量角器目前不支持从场景行号运行功能。 因此,除了状态之外,新的 testCase 结果没有太多我觉得有用的东西。

我希望 testCase 与使用带有 PickleFilter 的 getTestCasesFromFileSystem 时返回的结果相匹配。 我已经用它做了一些有趣的并行工作,以支持通过标签过滤场景以作为分片传递给量角器。 从该结果返回的信息要有用得多,我认为在 testCase 结果中非常有用。

PickFilter 的示例结果:

{ pickle: 
     { tags: [Object],
       name: 'Github test with page object',
       language: 'en',
       locations: [Object],
       steps: [Object] },
    uri: 'test/features/examples/github-example.feature' }

我并不是说它需要完全匹配,但我在这个结果中看到了很多其他人和我似乎会从中受益的东西。

如果你对我的例子感兴趣,我在这里使用它: https :

@charlierudolph这是设置 testCase 的地方吗?

https://github.com/cucumber/cucumber-js/blob/fbff6b0fae54d2e341ee247addc60a9f05753f1d/src/formatter/helpers/event_data_collector.js#L22

据我所知,在 testCase 旁边有一个关于 pickle 的参考。 那么为什么不从 pickle 结果中返回更多位到 testCase 结果中呢?

@gd46好的,让我们将pickle到传递给钩子的对象中,替换 sourceLocation。 需要在此函数中更新: https :

@charlierudolph ,我刚看到你的评论。 那很好啊! 我会尽快看看这个。 我很乐意做出贡献。

@charlierudolph只是想澄清一下变化。 我们是否可以接受不同之处在于 pickle 包含 uri 而没有像 sourceLocation 那样直接在其上显示行号。 如果有人希望使用带有行号的 uri,他们可以使用从 pickle 对象返回的行号? 我认为这没有问题,只是想确认一下。

我想让我们保留源位置对象(而不是删除它)并添加泡菜对象。

好的,这也适用于我。 所以我刚开始为黄瓜做贡献,我仍然试图理解它的结构。

正如您指出的需要更新的行,我相信我们可以在 sourceLocation 旁边添加类似这样的内容:

pickle: this.testCase.pickle

然后任何希望在钩子中使用它的人都可以按如下方式访问它:

testCase.pickle.tags
testCase.pickle.name
etc. 

我已经进行了更新,但我不是 100% 确定如何更新所有相关测试。 你能提供一些指导吗?

我能够通过将我的 fork 与我的本地项目之一的更改链接起来来测试更改。 完整的 testCase 结果将如下所示:

{
  "sourceLocation": {
    "uri": "test\/features\/examples\/example.feature",
    "line": 4
  },
  "pickle": {
    "tags": [
      {
        "name": "@example",
        "location": {
          "line": 3,
          "column": 3
        }
      }
    ],
    "name": "Custom Transform should take belly and capitalize it",
    "language": "en",
    "locations": [
      {
        "line": 4,
        "column": 3
      }
    ],
    "steps": [
      {
        "text": "I have cucumbers in my belly",
        "arguments": [

        ],
        "locations": [
          {
            "line": 5,
            "column": 10
          }
        ]
      }
    ]
  },
  "result": {
    "duration": 7,
    "status": "passed"
  }
}

在做了一些更多的测试之后,我注意到在我们可以在 test_case_runner 中访问它时,pickle 不包含 uri。 所以我认为保持源位置不变是可以的。

这就是 PickleFilter 返回 pickle 的内容:

{
    "pickle": {
      "tags": [
        {
          "name": "@example",
          "location": {
            "line": 3,
            "column": 3
          }
        }
      ],
      "name": "Custom Transform should take belly and capitalize it",
      "language": "en",
      "locations": [
        {
          "line": 4,
          "column": 3
        }
      ],
      "steps": [
        {
          "text": "I have cucumbers in my belly",
          "arguments": [

          ],
          "locations": [
            {
              "line": 5,
              "column": 10
            }
          ]
        }
      ]
    },
    "uri": "test\/features\/examples\/example.feature"
  }

因此,一切都将是相同的减泡菜,其中没有 uri。

打开一个 PR 来突出到目前为止的变化。 仍然需要更新测试。

致力于更新测试。 我设置了这个东西来更改我的本地 java 版本,并意识到这就是我无法运行某些功能测试的原因:/。

由于关闭后没有任何近期活动,因此该线程已自动锁定。 请为相关错误打开一个新问题。

此页面是否有帮助?
0 / 5 - 0 等级