我确实知道,基本上,技术定义中的所有GivenWhenThenAnd关键字都不会被Cucumber区分。但是,为什么Cucumber对于步骤定义@Given@When@Then@And具有不同的注释?

我正在观察的是您具有描述步骤的代码:

@When("^first operand = \"(.+?)\"$")
public void setFirstOperand(String firstOp){
    firstOperand = Integer.parseInt(firstOp);
}


,或者您具有代码:

@Then("^first operand = \"(.+?)\"$")
public void setFirstOperand(String firstOp){
    firstOperand = Integer.parseInt(firstOp);
}


都以相同的方式执行测试的逻辑。

Cucumber框架在这些不同注释下对待代码的方式是否有所不同?我认为应该有一些区别,否则这种体系结构(当您有不同的实体要处理相同的逻辑时)看起来就不是“面向对象的”。

评论

从技术上讲没有区别。

#1 楼

您的问题似乎几次被误解了,甚至您的评论也没有解决这种情况。我认为至少我正确地回答了您的问题-至少我发现非常清楚:这与DSL无关,而与测试步骤的注释有关。

不幸的是,我无法回答为什么黄瓜实际上对步骤定义具有不同的注释,但是我知道为什么如果我设计了API,那么我将设计具有这些不同注释的API。

我根本不是黄瓜的专家,但是我发现Given的语义与黄瓜的Gherkin规范中描述的方式非常矛盾。它会明智地开始:


给定的步骤用于描述系统的初始上下文-场景的场景。这通常是过去发生的事情。


完美!显然是先决条件,对吧?可能意味着如果不满足此先决条件,那么该方案将根本不适用。

相同描述的下一个句子破坏了这种希望:


当Cucumber执行一个给定步骤时,它将把系统配置为定义良好的状态,例如创建和配置对象或将数据添加到测试数据库。


这绝对不是我们所谓的关注点分离-我宁愿称其为关注点混乱。

为了将系统配置为处于良好定义的状态,我们通常需要执行带有@Before批注或类似内容的设置任务。

用自然英语(我不是母语人士)因此我可能会略有错误)Given引入了前提条件。这正是我们可以从特定的@Given注释中受益的地方(黄瓜似乎已经错过了这次机会):它可以(我认为应该)对一个布尔函数进行注释,该布尔函数指示测试(所有WhenThen都作为测试)以及是否应用了其他Given条件)。

用简单的话来说:理想情况下,如果不满足前提条件,则测试永远不会失败。这将大大提高测试数据的灵活性。

回到自然语言(嗯,有点半自然):
“鉴于您接受了会议。当会议开始时,我希望您能在会议室。”

我要说的是,其余所有内容仅在您接受会议后才适用。如果您不参加会议,那么会议可能也不会开始,即使会议开始了,我也不会期望您会在会议室。

这就是特定@Given批注的值所在的位置:测试运行器可以忽略所有测试或所有不符合前提条件的大纲记录。以与JUnit处理assumeThat类似的方式。

我可以想象API的设计者会想到类似的东西。也许在API设计完成之后,没有足够的时间来实现它,或者实现该解决方案的人们有不同的看法。

由于测试运行程序显然没有按照不同注释的方式实施,所以我想这就是您似乎正在意识到的:设计缺陷。

甚至更糟此漏洞会泄漏到DSL中。因为这意味着关键字也没有特定的语义。

很明显,在不破坏现有测试的前提下,无法引入现有DSL和API的增强语义-甚至更有可能甚至更糟:隐藏现有测试现在由滥用Given语义覆盖的错误。

对不起,您浪费了太多单词,再次没有回答您的问题。但是至少现在您有一个可以解决您问题的答案-并且您找到了一个痛苦的病人。

评论


除了对OP表示同情之外,我看不到此答案有任何附加值。

– Vishal Aggarwal
19-4-7在3:14



@Vhishal Aggarwal,很抱歉您看不到我的答案增加的任何价值。作为赔偿,我会尽力在您的评论中找到价值。

–yaccob
19年4月7日,下午3:29

@VishalAggarwal OP询问了Cucumber提供的不同注释之间的技术差异,您的答案没有解决。 yaccob提供了一些可能的理由,说明为什么会有多个批注似乎做完全相同的事情,这似乎是迄今为止最好的帖子

– Vivek Chavda
19年12月6日19:00

#2 楼

Cucumber解决的问题不是通信,而是体系结构。
这些关键字只是语法糖,用于业务用户的理解和可读性。技术上没有区别。
说过,整个黄瓜(BDD)的概念是要有一个通用的共享词汇表(DSL),以便所有团队成员都可以在同一水平上进行交流,包括非技术人员。 />
通过共享词汇改善交流,对于整个团队而言,这是有价值的。

就编码而言,

函数的工作是要返回应用程序的当前状态,
测试的工作是根据给定的测试场景确定(确认)它是肯定的还是否定的
,并相应地通过或失败测试。
br />
因此,函数可以返回相同的状态,该状态可能由测试脚本根据当前正在验证的方案确定为肯定/否定。

评论


感谢您的回答!但是似乎您正在谈论功能定义。如果我们谈论“用户”,那么这种方法可能有意义,但是我们谈论的是由编码人员为编码人员编写的编程框架。在这种情况下,更好的可读性意味着更好的结构和遵循的OOP编程最佳实践。对于程序员而言,如果有诸如“ @StepDef(type = EStepType.GIVEN,regexp =“ ...”)之类的注释,它将更具可读性。

– Alexey R.
18年7月18日在9:39

黄瓜(BDD)的整个概念是拥有一个通用的共享词汇表(DSL),因此所有团队都可以在包括非技术人员在内的同一级别上使用它进行通信。

– Vishal Aggarwal
18年7月18日在9:55



是的,但是作为开发人员,您将从该步骤中获得的价值将是“给出”或“何时或何时”,如果实现或逻辑上没有区别。这只会增加代码的不确定性,因为您将步骤编码为“给定”,但用户将能够像使用“步骤”那样使用它。

– Alexey R.
18年7月18日在9:57

没有明确语义的词汇表不是DSL。而且我怀疑共享三个可以任意互换的单词会改善交流。

–yaccob
19-4-7在3:59



如果黄瓜规格不符合您的要求,我深感抱歉。我了解您的担忧,但是如果需要对黄瓜进行更新/修复,最好使用黄瓜问题回购协议。

– Vishal Aggarwal
19年4月7日在13:17

#3 楼

诸如Given,When,And,But,Then之类的黄瓜关键字用于增强QA计划在场景中测试的场景的可读性和理解能力。

BDD框架的思想像黄瓜一样,是为了增强对测试层之外的人员(例如BA和开发人员或产品所有者)进行测试的知识。

典型方案的语法如下:

Scenario: Some determinable business situation

Given some precondition exists

And some other precondition exits

When some action by the actor

And some other action

And yet another action

Then some testable outcome is achieved

And something else have also happened


#4 楼

区别在于设计而不是功能

由于似乎对已接受和给出的答案有些不满意,我想将其总结一下,冒着只给线程添加一些噪音的风险。 >
您的问题的答案是……只是“ jada jada”与给定的“ jada jada”有所区别,并分别调用测试代码的另一部分,尽管它们具有相同的名称(区别不大)。 br />
Jithu Paul恰当地写道:


像黄瓜这样的BDD框架的想法是增强对外部人员正在测试的内容的了解。测试层,例如BA或产品所有者。


这并不意味着(完全?)技术意义上的“带来功能”(就像编程语言中的不同关键字一样),而是将您的测试框架“翻译”为非技术实例,反之亦然(例如,支持通知单等)。提到的关键字仅旨在传递语法糖以使其“像英语一样”可读。

那是我想展示一个如何区分它们的示例:


给出了先决条件(例如“我是登录用户”)-
..因此可能涉及许多步骤,例如导航到登录表单,填写值,单击按钮等。此先决条件带有可以(应该?)检查的期望(〜最终函数本身的断言)。
何时描述单个步骤(例如,“我单击文章链接”)-
..因此,它主要不是经过测试的功能的一部分。我很少对照期望检查它们(因为我会经常测试两次代码)。与“给定”步骤的主要区别在于,“何时”步骤更为简单。我在这里放置了对当前功能至关重要的所有内容,只是不要最终重复自己。
然后步骤验证期望值(例如,“我应该查看文章列表”)-
..这意味着它们根本不像前两个:它们返回true和false(而不是一个动作),并确定“向外部世界”代码的进度和质量。

显然,所有关键字都执行相同的操作:执行(任何)代码。您可以(也不应)仅使用其中之一编写测试。 (再次:Gherkin是为非技术角色编写的)。

最后,如果按照建议的步骤进行操作,就不会重复自己,并且拥有更具可读性和可维护性的代码库(对于开发人员可以快速而干净地工作。)

如果您以开发人员的身份为自己的项目进行视图和控制器测试,我不建议您完全使用Cucumber,而是使用更多技术框架列出您的规格。
(这里我并不是从Java角度来看的,因为到目前为止,我只将黄瓜用于红宝石,但是原理是相同的。)在幕后,Cucumber使用了另一种语言,也许还有框架。因为您熟悉它们,所以请使用它们,除非您需要翻译规范或让非技术人员可以选择编写自己的规范(然后必须实施)。

评论


根本不是一个声音,但确实是有价值的答案。谢谢!

– Alexey R.
20年4月8日在15:44

#5 楼

通常,您在给定的步骤中设置场景,这可能是连接到服务,加载其配置,启动其固定装置

在when步骤中您要测试的主要动作时,这可能是用户请求或采取操作的服务。

您可以将操作与和步骤链接起来。

最后一步将验证操作是否发生,这可以通过断言结果数据或状态。

通过良好的步骤设计,您可以在功能之间重复使用步骤以提高覆盖范围和效率。

最好通过对步骤进行仔细的参数化以使其可扩展来实现。

您还可以使用功能部件中的表来每次使用表行中的不同数据多次运行一个步骤。

还可以对硬编码到要素线中的值运行相同的步骤。

除了循环使用表外,这些函数的调用方式没有区别黄瓜比任何其他。至少在我见过的大多数实现中,但您的情况可能有所不同。
您可以在调试器中运行它并进行检查。

诸如SpecFlow之类的一些自定义工具会传递各种其他对象和状态,以允许您构建要测试的方案。