大家应该都回来上班了。先祝大家新年好!今天为大家介绍一下 Cucumber 的最佳实践,特别是 Cucumber.js。

Cucumber 是用自然语言编写的自动化测试框架。因为它可以用中文编写可执行的用例,所以你团队中的任何人都可以阅读它们。因为任何人都可以阅读它们,所以可以用它来帮助改善团队之间的沟通,协作和信任。

Cucumber 支持 JavaScript、Python、Java、Ruby 等语言,你可以使用自己熟悉的编程语言来开发基于 Cucumber 的自动化脚本。近年来 Node.js 的兴起,我们使用 JavaScript 就可以开发 Web 端,手机端,以及桌面端应用,使得 JavaScript 越来越成为全栈工程师的首选语言,本次也主要以 Cucumber 的 JavaScript 实现为例,介绍在开发 Cucumber 自动化脚本中的最佳实践。

如果对 Cucumber 还不太了解的同学可以阅读上篇文章 Cucumber 基础介绍:Cucumber 是如何运行的?

一、组织目录结构

Cucumber.js 项目目录的组织结构如下:

├─features
│  ├─step_definitions
│  │  └─definitions.js
│  └─support
│  │  └─env.js
│  └─feature1.faeture
└─reports

Cucumber.js 项目中:
features 目录主要是剧本 (*.feature) 文件和脚本映射文件目录
reports 为测试报告生成目录

在 features 目录下:
*.feature: 剧本文件,可任意放置,只要是在 features 目录下,或它的子目录下。
*.js: 操作步骤对应的自动化代码实现,一般放在 step_defintions 目录中,但也可根据需要任意放置在 features 目录下或它的子目录下。

使用 BDD 行为驱动模式开发自动化代码,从根本上已经将用例与代码很好的分开了,既做了关联又实现了松耦合。当项目越来越大,文件也会越来越多时,良好的项目文件结构规划会让你的项目更清晰更易于管理。

1. features 目录

在执行脚本的时候,默认是从 features 中开始查找剧本文件(*.feature 文件),所以我们所有的剧本文件和步骤定义代码都必须定义在 features 目录下。

剧本文件比较多的时候,可以在 features 中以功能区分来建立不同的目录,某个功能对应的多个 feature 文件放在一个目录下。

2. 设计页面对象模型 (POM)

Web 自动化测试,页面很多,页面元素不易管理,于是有人提出 POM 管理方式。在 Cucumber 中,完全可以使用 POM。如果做 Web 自动化,可以考虑下面的目录结构:

project          (项目目录)
    features     (feature文件目录)
    libraries    (自定义库文件)
    config       (配置文件)

在 libraries 目录中,对于 Web,Mobile 项目,这个目录可以放置常用的操作函数,页面元素定位定义信息。推荐这样的目录结构:

libraries
    selectors
    actions

selectors:存储页面元素定位信息
actions:常用操作

把常用操作定义在 actions 目录中,常用操作中引用 selectors 中每一个元素控件,features 文件中的步骤定义可以调用这些封装好的常用操作。

这样做的好处:被测应用版本更新,业务流程如果不变,只是界面更改,只需要去 selectors 中修改相应的元素定位即可。

另外,如果是在做 Windows 界面自动化,可以使用 Cucumber.js 的自动化开发工具 CukeTest,它内置有模型管理器,可以用来管理测试对象。

3. 项目结构

归纳上述信息,项目的整体目录大致如下:

project-name
    config
    featrues
        a.feature
        definitions
            step.js
        support
            env.js
            hooks.js
    node_modules
    libraries
        selectors
        actions
    reports
    package.json        

config,项目运行配置目录
features,存放所有运行场景,可以根据应用的不同功能用不同目录存放 feature 文件。
definitions,存放自动化代码实现目录。
support,运行时配置(配置脚本运行超时时间以及脚本执行时配置)。
node_modules,依赖库
libraries,自定义库文件
selectors UI,自动化页面元素定位文件
actions,常用界面操作
reports,项目运行报告
package.json,项目依赖文件

二、场景运行

Cucumber.js 默认的运行场景的方式是在命令行模式下执行 node_modules.bin\cucumber-js ,它会运行 features 目录下所有的场景。

当用例数量多时,如果使用默认方式运行项目,会把所有场景执行一遍。这样会有一些问题:总执行时间较长,有些场景我们不想去执行但也被执行。因此,可以考虑以下的执行方式:

  1. 添加标签方式

Cucumber 在执行的的时候支持使用标签的方式为不同的场景或者剧本文件添加标签。

标签可以被添加到一个剧本文档的不同元素上,包括剧本 (Feature)、场景 (Scenario) 和示例 (Example) 等。每个标签必须以"@"作为前缀。
例如下面例子:

#language: zh-CN
@math
功能: 加法
  为了避免一些愚蠢的错误
  作为一个数学白痴
  我希望有人告诉我数字相加的结果

  @sanity
  场景: 两个数相加
    假如我已经在计算器里输入6
    而且我已经在计算器里输入7
    当我按"相加"按钮
    那么我应该在屏幕上看到的结果是13

  @uat
  场景大纲: 三个数相加
    假如我已经在计算器里输入<数据1>
    而且我已经在计算器里输入<数据2>
    而且我已经在计算器里输入<数据3>
    当我按"<操作按钮>"按钮
    那么我应该在屏幕上看到的结果是<结果>
    例子: 
      | 数据1 | 数据2 | 数据3 | 操作按钮 | 结果 |
      | 12    | 2    | 3     | 相加     | 17  |
    @complete
    例子: 
      | 数据1 | 数据2 | 数据3 | 操作按钮 | 结果 |
      | 242   | 111  | 23    | 相加    | 376  |

运行时加上 --tag 即可运行带有这些标签的所有场景。
在 CukeTest 中,你可以直接在运行配置中设置要执行的标签:

如果我们的项目中有很多标签,执行时可使用一个或多个标签,用 AND 或 OR 组合形成标签表达式来过滤。例如上面的剧本文件中, @math and @sanity 表达式会执行第一个场景,即 “两个数相加”。 @sanity or @uat 会执行第一个场景 “两个数相加” 和第二个场景大纲 “三个数相加”。@complete 只会用它标记的那个表格数据执行场景大纲。

2. 标签过滤框

标签过滤框是 CukeTest 可视 界面中特有的功能, 点击菜单查看-> 过滤标签…,一个过滤框就会显示出来。

标签过滤框可用于过滤一个剧本文档以供显示或执行。输入标签名称并按下回车键,文档将只显示符合标签的场景。除了手动输入标签名外,您也可以单击下拉箭头来选择文档中的某个标签。

输入标签后,您可以点击过滤框中的箭头按钮来运行带有这些标签的场景,其它不匹配标签的场景将不会被运行。

3. 顺序执行 feature 文件

Cucumber.js 命令行模式支持运行单个 feature 文件或者运行某个目录里所有的 feature 文件,常用执行如下:

$ cucumber-js features/**/*.feature    运行features目录下所有feature文件
$ cucumber-js features/dir             运行features/dir目录下所有文件
$ cucumber-js features/my_feature.feature 仅运行my_feature.feature文件

某些情况下,需要顺序执行特定 feature 文件。为了能顺序运行 feature 文件,可以在 Cucumber.js 编辑器 CukeTest 中进行配置,操作如下:

打开 运行配置文件 -- 运行序列

在 运行序列 中添加 feature 文件,运行时会根据添加的 feature 文件顺序来执行。

4. Hooks 设置

Cucumber.js 使用 BeforeAll , Before , After ,AfterAll 定义所有的场景和每个场景执行之前,执行之后的操作。这些执行是针对所有的场景设置的。

如果项目过大,针对每一个场景都设置 hooks 并不能完全兼顾所有需求,比如在某个 Web 自动化测试中,需要一部分操作是在用户登录状态下进行的,另一部分操作是在非用户登录状态下进行的。这种情况,可以在 feature 文件中为相应的场景打上对应的标签,在 Hooks 中以@tags 方式设置带有此标签的场景之前运行或者之后运行。

Before({tags: "@foo"}, function () {
  // 所有带@foo标签场景运行之前执行
});

Before({tags: "@foo and @bar"}, function () {
  // 同时带有@foo和@bar标签场景之前执行
});

Before({tags: "@foo or @bar"}, function () {
  // 带有 @foo 或者 @bar标签场景之前执行
});

Before("@foo", function () {
  // 所有带@foo标签场景运行之前执行
});

三、运行报告

Cucumber.js 运行完成后测试报告默认会以文本模式打印到命令行界面,也可以通过添加参数 --json 将测试结果保存到 json 文件中去。

拿到运行结果 json 文件,可以自己解析文件中的数据,实现自定义图文报表。可以参考如下:

(Cucumber.js 自动化开发工具 CukeTest 生成报告截图)

四、运行时屏幕录制

对于 Web 自动化,或者 Windows 应用自动化完成后,如果个别场景出现了错误,需要排查是系统的 bug 还是自动化脚本的问题。为了方便定位问题,可以在自动化执行过程中进行屏幕录制,获得运行自动化的视频。

Cucumber.js 中不带有这个功能,要实现此功能,需要使用一些第三方的库自己来进行实现;自己实现过程中需要考虑到录屏文件大小,多屏录制等问题。如果自己没有处理过屏幕录制,也可以直接使用 Cucumber.js 开发 CukeTest 内置的屏幕录制功能。

总结

Cucumber 在目前社区中越来越流行,很多开发工具也都有基于 Cucumber 的插件,或者专门的工具。比如 VS Code 中就有不少于 10 个关于 Cucumber 的插件,另外还有针对 Cucumber.js 的开发工具 CukeTest,提供了可视化的操作界面和其它扩展功能。这些工具的出现提高了 Cucumber 的开发效率,让脚本开发更容易,感兴趣的同学可以都试一下。

如果你有什么 Cucumber 的最佳实践这里没有提到,或者有什么相关的疑问还没有解决,欢迎留言,一起讨论~


↙↙↙阅读原文可查看相关链接,并与作者交流