场景中的变量传递

由于Cucumber中,每个步骤都是独立的、相互隔离的,那么如何在步骤间传递变量呢?比如说上一个步骤中操作得到的结果,需要在下一个步骤中验证结果是否正确该怎么做呢?比起使用全局变量,其实Cucumber推荐的是另一种方法,这里就要提到一个概念——World对象,每个Hook和场景中维护着一个World对象(类似HTML中的document对象或NodeJS中的global对象)用于保存场景中的变量、函数等内容。

因此使用World对象进行步骤间的变量传递就非常简单了,在步骤中将需要传递的变量赋值给World对象,接着在同个场景的其它步骤中,取出该值即可。

并且在所有的步骤定义中,都可以使用this关键字直接访问World对象,如下:

  1. Given("加号左边为1", async function () {
  2. this.leftValue = 1;
  3. });

运行上述步骤后,场景中的World对象就会多出一条leftValue属性,并且值为1。

在步骤间传递变量

前文提到,如果上一个步骤中操作得到的结果,需要在下一个步骤中验证结果是否正确,这一过程如何借助World对象来实现呢?我们定义一个简单的场景,场景中完成的是简单的加法运算,以及对运算结果的校验,如下:

  1. # language: zh-CN
  2. @math
  3. 功能: 数学计算
  4. 加法测试,Cucumber 3.x 样例
  5. 场景: 简单数学计算
  6. 假如加号左边为1
  7. 当加号右边为1
  8. 那么结果为2

那么代码定义如下:

  1. const { Given, When, Then } = require('cucumber');
  2. //// 你的步骤定义 /////
  3. Given("加号左边为{int}", async function (leftSideValue) {
  4. this.leftValue = leftSideValue;
  5. });
  6. When("加号右边为{int}", async function (rightSideValue) {
  7. this.rightValue = rightSideValue;
  8. });
  9. Then("结果为{int}", async function (expectedResult) {
  10. actualResult = this.leftValue + this.rightValue; // 实际运算结果
  11. if (actualResult === expectedResult) {
  12. this.attach(`运算结果符合预期,为${actualResult}`);
  13. } else {
  14. throw `运算结果不符合预期,预期值为${expectedResult},实际结果为${actualResult}`;
  15. }
  16. });

运行结果如下:
场景中的变量传递运行结果

在上述代码中,在前两个步骤的定义中,将要用到的变量使用World对象来传递,以便第三步中使用。除了比较操作结果外,另一种常见的情况是,在场景开始前和结束后都进行一次截图,并比较两次截图(使用工具箱中的imgCompare(img1, img2)方法),使用World对象传递截图也是非常方便的。

此外,代码中还使用了this.attach()的方法,这是World对象自带的一个方法,能够将指定内容作为 附件(Attachment) 添加到报告中,适合用于在报告中加入验证结果、测试数据、运行截图等等内容。了解更多附件相关的内容可以点击查看

在Hook中使用变量传递

在上一节中提到了,World对象不仅存在于场景中,Hook中也同样存在,因为Hook在运行时也会被当作场景或者剧本的一部分。更具体的描述是,Hook中的BeforeAfter与场景共用一个World对象,因此在这两个Hook中可以定义一些供场景使用的值。将上面的代码稍微修改以后如下:

  1. # language: zh-CN
  2. @math
  3. 功能: 数学计算
  4. 加法测试样例
  5. 场景: 简单数学计算
  6. 假如加号左边为1
  7. 当加号右边为1
  8. 那么结果为2
  9. #+++++++++++++++++++++++++++++++++#
  10. @complex @math
  11. 场景大纲: 混合场景
  12. 假如加号左边为<var>
  13. 当加号右边为<increment>
  14. 那么结果为<result>
  15. 例子:
  16. | var | increment | result |
  17. | 100 | 5 | 105 |
  18. | 101 | 5 | 106 |
  19. | 0 | -10 | -10 |
  20. #+++++++++++++++++++++++++++++++++#
  1. const { Given, When, Then } = require('cucumber');
  2. //// 你的步骤定义 /////
  3. Given("加号左边为{int}", async function (leftSideValue) {
  4. this.leftValue = leftSideValue;
  5. });
  6. When("加号右边为{int}", async function (rightSideValue) {
  7. this.rightValue = rightSideValue;
  8. });
  9. Then("结果为{int}", async function (expectedResult) {
  10. /*++++++++++++++++++++++++++++++++++++++++*/
  11. if (this.fromBeforeAll) {
  12. this.attach(this.fromBeforeAll);
  13. }
  14. if(this.location) {
  15. this.attach(this.location);
  16. }
  17. /*++++++++++++++++++++++++++++++++++++++++*/
  18. actualResult = this.leftValue + this.rightValue;
  19. if (actualResult === expectedResult) {
  20. this.attach(`运算结果符合预期,为${actualResult}`);
  21. } else {
  22. throw `运算结果不符合预期,预期值为${expectedResult},实际结果为${actualResult}`;
  23. }
  24. });
  25. /*+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/
  26. const { Before, BeforeAll } = require('cucumber');
  27. Before(async function (testCase) {
  28. this.location = `运行位置: feature文件第${testCase.sourceLocation.line}行`;
  29. })
  30. BeforeAll(async function () {
  31. this.fromBeforeAll = `这是BeforeAll Hook传递的信息`;
  32. })
  33. /*+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/

运行结果为:
Hook中的变量传递运行结果

这里的BeforeHook中传递的变量值为运行时场景在剧本文件中的行数,对比剧本文件也能看的出来。而场景大纲中示例表的每行数据都会被渲染为一个完整的场景,因此后面三个场景各指向一行示例表的数据。了解更多关于场景大纲示例表的内容可以点击查看