最近,项目上出于系统性稳定性、减少测试工作量考虑,打算在 web 前端引入 bdd。由于上一个项目写了一定的 cucumber 代码(bdd 测试框架之一),这个框架选型的责任便落到了我的肩膀上了。
在我们进行框架选型的时候,着重考虑了一个因素:测试实现脚本是由开发人员编写的,因此最好寻找 javascript 支持的框架。在搜索了一天后,选择了三个框架 cucumber、robot、gauge。以下是上述的三个框架入选的原因:
cucumber,团队的开发人员有一些有相关的开发经验、支持 javascript。
robot framework,测试人员接受过相关的培训、不支持 javascript。
gauge,可以生成更好的测试报告及自由的书写、支持 javascript。不过,主要是我写腻了 cucumber。
随后,便使用三个不同的框架写了几个 ui 测试的 demo。在开始之前,让我们了解什么是 bdd。
bdd
behavior driven development,行为驱动开发是一种敏捷软件开发的技术,它鼓励软件项目中的开发者、qa 和非技术人员或商业参与者之间的协作。
与一般的自动化测试(如单元测试、服务测试、ui 测试)不一样的是,bdd 是由多方参与的测试开发方式。如在使用 protractor 写 angular 的 e2e 测试的时候,所以的测试都是前端测试人员编写的。bdd 最重要的一个特性是:由非开发人员编写测试用例,而这些测试用例是使用自然语言编写的 dsl(领域特定语言)。
换多话来说,业务人员、测试人员、客户等利益相关者,以习惯的方式编写相关的测试用例,再由开发人员去实现相关的测试。如下图所示:
bdd 流程
由业务人员编写的测试用例,将是使用如下的形式实现的:
* 当我在网站的首页
* 输入用户名 demo
* 输入密码 mode
* 提交登录信息
* 用户应该跳转到欢迎页
对于能支持中文的 bdd 框架来说,这就是业务人员和测试人员等编写的用例,他们能轻松地编写出这样的用例,而开发人员便是去实现这一个又一个的 dsl 语句。
在我之前的一个项目里,我们遇到了一个问题:测试用例也是由开发人员编写的。这种做法不仅不能体现 bdd 的价值,而且对于开发人员来说,这是在糟蹋代码。如果完全是由开发人员编写的测试,那么为什么我们需要写一个额外的 dsl 层呢?
接下来,让我们看看三个测试的一个简单对比表:
bdd 框架对比: cucumber.js vs robot framework vs gauge.js
x
cucumber
gauge
robot
编程语言支持
java,ruby,javascript 等 13 种语言
java, javascript, ruby 等 6 种语言
python, java, c
支持的系统
所有主流系统
多语言支持
utf-8
用户关键字及用例层面支持utf-8
中文社区支持
完善
待完善
report
js 不支持 html
粗粒度
细粒度
失败时截图
不支持
支持
从某程程度上来看,三个框架差不了多少,每个框架也各自都有自己的问题。
cucumber 的 javascript 版本不支持 html 的报表生成。
gauge 虽然比较适合我们的要求,但是相关的中文资料比较少。
robot 主要的问题是不支持 javascript,以及要按 robot 定义的方式来编写代码。
以下是三个框架的示例及详细的对比。
cucumber.js
cucumber 是一个能够理解用普通语言 描述的测试用例的支持行为驱动开发(bdd)的自动化测试工具,用ruby编写,支持java和.net等多种开发语言。
使用自然语言,更易读
支持表格参数
支持多种格式的report:html、junit etc.
支持多种语言
支持四种状态的测试步骤:passed、failed、skipped、pending
支持使用变形器消除重复
一个商用的在线 cucumber 系统:cucumber pro
dsl code examples
示例代码:https://github/phodal/bdd-frameworks-compare/tree/master/cucumber
# language: zh-cn
功能: 失败的登录
场景大纲: 失败的登录
假设 当我在网站的首页
当 输入用户名
当 输入密码
当 提交登录信息
那么 页面应该返回 error page
例子:
|用户名 |密码 |
| 'jan1' | 'password' |
| 'jan2' | 'password' |
cucumber 支持比较固定的 dsl 格式,即三段式 given-when-then,对应的中文便是:假设-当-那么。作为一个历史悠久的框架,它的中文资料相当的丰富,只是在 javascript 方面有些不足,不能生成对应的 html 报告。
其实现代码如下所示:
step code examples
definesupportcode ( function ({ given , when , then }) {
given ( '当我在网站的首页' , function () {
return this . driver . get ( 'http://0.0.0.0:7272/' );
});
when ( '输入用户名 {string}' , function ( text ) {
return this . driver . findelement ( by . id ( 'username_field' )). sendkeys ( text )
when ( '输入密码 {string}' , function ( text ) {
return this . driver . findelement ( by . id ( 'password_field' )). sendkeys ( text )
when ( '提交登录信息' , function () {
return this . driver . findelement ( by . id ( 'login_button' )). click ()
then ( '页面应该返回 {string}' , function ( string ) {
this . driver . gettitle (). then ( function ( title ) {
expect ( title ). to . equal ( string );
从代码实现上来说,也是固定的三段式。其底层依赖于 selenium,因此写法上与 gauge 的区别并不大。
robot framework
robot framework是一款python编写的功能自动化测试框架。具备良好的可扩展性,支持关键字驱动,可以同时测试多种类型的客户端或者接口,可以进行分布式测试执行。
关键特性:
使用关键字的机制,更容易上手
提供了ride,对于不熟悉编码的人来说比较友好
能够精细的控制关键字的scope
log 和 report 非常好
使用变量文件的机制来描述不同的环境
丰富的关键字库
内置变量
示例代码:https://github/phodal/bdd-frameworks-compare/tree/master/robot
*** settings ***
documentation 登录测试 2
...
suite setup 打开浏览器到登录页 1
suite teardown close browser
test setup 转到登录页
test template 使用错误的失败凭据应该登录失败
resource resource . robot
*** test cases *** user name password
无效的用户名 invalid $ { valid password }
无效的密码 $ { valid user } invalid
无效的用户名和密码 invalid whatever
*** keywords ***
使用错误的失败凭据应该登录失败
[ arguments ] $ { username } $ { password }
输入用户名 $ { username }
输入密码 $ { password }
提交登录信息
登录应该不成功
location should be $ { error url }
title should be error page
从上面的代码来看,robot 在某些特定的关键字上,必须使用英语。在关键的代码如关闭浏览器,仍然需要使用 close browser 英语这些来实现。
打开浏览器到登录页
open browser $ { login url } $ { browser }
maximize browser window
set selenium speed $ { delay }
login page should be open
title should be login page
转到登录页
go to $ { login url }
输入用户名
[ arguments ] $ { username }
input text username_field $ { username }
输入密码
[ arguments ] $ { password }
input text password_field $ { password }
click button login_button
应该跳转到欢迎页
location should be $ { welcome url }
title should be welcome page
与上面的 cucumber 相比,robot 对于英语的非开发人员来说更加友好。换句话来说,robot 更像是一个适合于 qa 的语言。作为一个开发人员,可能不太喜欢这种形式。
报告示例
不过,robot 提供了一份说尽的报告。细致的展示了每一个测试,以及其步骤时间等等。
robot framework report
gauge
gauge 是 go 开发的一个跨平台测试自动化工具。它给作者提供了用商业语言测试用例的能力。
基于 markdown 的丰富的标记
支持用任何程序语言来编写测试代码
支持 plugin 的模块化架构
跨语言实现一致性。
简单,灵活和丰富的语法
开源的,因此它可以自由共享,同时被他人改进
商业语言测试 : 支持可执行文件的概念
帮助您创建可维护和可理解的测试套件
支持外部数据来源
ide support
示例代码:https://github/phodal/bdd-frameworks-compare/tree/master/gaugejs
失败的登录
===
|--------|--------|
| jan1 | password |
| jan2 | password |
-----------
* 输入用户名
* 输入密码
* 页面应该返回 error page
与 robot 和 cucumber 不一样的是,gauge 使用的是大家更熟悉的 markdown 形式的 dsl。并且从形式上来说,更加自由。list 中的每一行,就代表着一个元素。因此,其对应的实现代码也更加的自由。
step ( 当我在网站的首页 , async function () {
await page . goto ( 'http://0.0.0.0:7272/' );
step ( 输入用户名 , async function ( query ) {
await page . click ( '#username_field' );
await page . type ( query )
step ( 输入密码 , async function ( query ) {
await page . click ( '#password_field' );
step ( 提交登录信息 , async function () {
await page . click ( '#login_button' )
step ( 页面应该返回 , async function ( query ){
await page . waitfor ( 'h1' );
const text = await await page . $eval ( '#container h1' , h1 =>{
return h1 . innerhtml ;
expect ( text ). to . equal ( query );
上面采用的是 node.js 8 支持的异步写法,除此与 cucumber.js 写的代码并没有太多的差异。
至于,gauge 生成的 ui 并没有 robot 那么详细,但是看上去现代。
gauge report
那么,哪个框架,你更喜欢呢?