场景中的变量传递
由于Cucumber中,每个步骤都是独立的、相互隔离的,那么如何在步骤间传递变量呢?比如说上一个步骤中操作得到的结果,需要在下一个步骤中验证结果是否正确该怎么做呢?比起使用全局变量,其实Cucumber推荐的是另一种方法,这里就要提到一个概念——World对象,每个Hook和场景中维护着一个World
对象(类似HTML中的document
对象或NodeJS中的global
对象)用于保存场景中的变量、函数等内容。
因此使用World
对象进行步骤间的变量传递就非常简单了,在步骤中将需要传递的变量赋值给World
对象,接着在同个场景的其它步骤中,取出该值即可。
并且在所有的步骤定义中,都可以使用this
关键字直接访问World
对象,如下:
Given("加号左边为1", async function () {
this.leftValue = 1;
});
运行上述步骤后,场景中的World
对象就会多出一条leftValue
属性,并且值为1。
在步骤间传递变量
前文提到,如果上一个步骤中操作得到的结果,需要在下一个步骤中验证结果是否正确,这一过程如何借助World
对象来实现呢?我们定义一个简单的场景,场景中完成的是简单的加法运算,以及对运算结果的校验,如下:
# language: zh-CN
@math
功能: 数学计算
加法测试,Cucumber 3.x 样例
场景: 简单数学计算
假如加号左边为1
当加号右边为1
那么结果为2
那么代码定义如下:
const { Given, When, Then } = require('cucumber');
//// 你的步骤定义 /////
Given("加号左边为{int}", async function (leftSideValue) {
this.leftValue = leftSideValue;
});
When("加号右边为{int}", async function (rightSideValue) {
this.rightValue = rightSideValue;
});
Then("结果为{int}", async function (expectedResult) {
actualResult = this.leftValue + this.rightValue; // 实际运算结果
if (actualResult === expectedResult) {
this.attach(`运算结果符合预期,为${actualResult}`);
} else {
throw `运算结果不符合预期,预期值为${expectedResult},实际结果为${actualResult}`;
}
});
运行结果如下:
在上述代码中,在前两个步骤的定义中,将要用到的变量使用World
对象来传递,以便第三步中使用。除了比较操作结果外,另一种常见的情况是,在场景开始前和结束后都进行一次截图,并比较两次截图(使用工具箱中的imgCompare(img1, img2)
方法),使用World
对象传递截图也是非常方便的。
此外,代码中还使用了this.attach()
的方法,这是World
对象自带的一个方法,能够将指定内容作为 附件(Attachment) 添加到报告中,适合用于在报告中加入验证结果、测试数据、运行截图等等内容。了解更多附件相关的内容可以点击查看。
在Hook中使用变量传递
在上一节中提到了,World
对象不仅存在于场景中,Hook中也同样存在,因为Hook在运行时也会被当作场景或者剧本的一部分。更具体的描述是,Hook中的Before
、After
与场景共用一个World
对象,因此在这两个Hook中可以定义一些供场景使用的值。将上面的代码稍微修改以后如下:
# language: zh-CN
@math
功能: 数学计算
加法测试样例
场景: 简单数学计算
假如加号左边为1
当加号右边为1
那么结果为2
#+++++++++++++++++++++++++++++++++#
@complex @math
场景大纲: 混合场景
假如加号左边为<var>
当加号右边为<increment>
那么结果为<result>
例子:
| var | increment | result |
| 100 | 5 | 105 |
| 101 | 5 | 106 |
| 0 | -10 | -10 |
#+++++++++++++++++++++++++++++++++#
const { Given, When, Then } = require('cucumber');
//// 你的步骤定义 /////
Given("加号左边为{int}", async function (leftSideValue) {
this.leftValue = leftSideValue;
});
When("加号右边为{int}", async function (rightSideValue) {
this.rightValue = rightSideValue;
});
Then("结果为{int}", async function (expectedResult) {
/*++++++++++++++++++++++++++++++++++++++++*/
if (this.fromBeforeAll) {
this.attach(this.fromBeforeAll);
}
if(this.location) {
this.attach(this.location);
}
/*++++++++++++++++++++++++++++++++++++++++*/
actualResult = this.leftValue + this.rightValue;
if (actualResult === expectedResult) {
this.attach(`运算结果符合预期,为${actualResult}`);
} else {
throw `运算结果不符合预期,预期值为${expectedResult},实际结果为${actualResult}`;
}
});
/*+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/
const { Before, BeforeAll } = require('cucumber');
Before(async function (testCase) {
this.location = `运行位置: feature文件第${testCase.sourceLocation.line}行`;
})
BeforeAll(async function () {
this.fromBeforeAll = `这是BeforeAll Hook传递的信息`;
})
/*+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/
运行结果为:
这里的Before
Hook中传递的变量值为运行时场景在剧本文件中的行数,对比剧本文件也能看的出来。而场景大纲中示例表的每行数据都会被渲染为一个完整的场景,因此后面三个场景各指向一行示例表的数据。了解更多关于场景大纲与示例表的内容可以点击查看。