前端测试方法+工具

天气小雨,不宜出门。只好在家好好修炼,正好准备总结一下测试相关的知识。主要总结以下项目中用到的前端测试工具:

  1. mocha-phantomjs+chai来实现自动化单元测试
  2. nightWatch 实现端到端的集成测试

前端测试方法+工具

mocha+chai

Mocha(发音”摩卡”)诞生于2011年,是现在最流行的JavaScript测试框架之一,在浏览器和Node环境都可以使用。Mocha的作用是运行测试脚本,通常,测试脚本与所要测试的源码脚本同名,但是后缀名为.test.js(表示测试)或者.spec.js(表示规格)。比如,add.js的测试脚本名字就是add.test.js。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
// add.js
function add(x, y) {
return x + y;
}
module.exports = add;
// add.test.js
var add = require('./add.js');
var expect = require('chai').expect;
describe('加法函数的测试', function() {
it('1 加 1 应该等于 2', function() {
expect(add(1, 1)).to.be.equal(2);
});
});

上面这段代码,就是测试脚本,它可以独立执行。测试脚本里面应该包括一个或多个describe块,每个describe块应该包括一个或多个it块。
describe块称为”测试套件”(test suite),表示一组相关的测试。它是一个函数,第一个参数是测试套件的名称(”加法函数的测试”),第二个参数是一个实际执行的函数。
it块称为”测试用例”(test case),表示一个单独的测试,是测试的最小单位。它也是一个函数,第一个参数是测试用例的名称(”1 加 1 应该等于 2”),第二个参数是一个实际执行的函数。

chai是一个断言库,断言的意思类似于语言,就是1+1应该等于2,描述类似的这样的预言,断言和预言的区别在于断言的结果是必定发生的,断言的结果是准确的,如果发生错误只可能是执行断言的函数发生了错误,所以就可以定位是测试的函数有bug。所有的测试用例(it块)都应该含有一句或多句的断言。它是编写测试用例的关键。断言功能由断言库来实现,Mocha本身不带断言库,所以必须先引入断言库。

1
var expect = require('chai').expect;

断言库有很多种,Mocha并不限制使用哪一种。上面代码引入的断言库是chai,并且指定使用它的expect断言风格。
expect断言的优点是很接近自然语言,下面是一些例子。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
// 相等或不相等
expect(4 + 5).to.be.equal(9);
expect(4 + 5).to.be.not.equal(10);
expect(foo).to.be.deep.equal({ bar: 'baz' });
// 布尔值为true
expect('everthing').to.be.ok;
expect(false).to.not.be.ok;
// typeof
expect('test').to.be.a('string');
expect({ foo: 'bar' }).to.be.an('object');
expect(foo).to.be.an.instanceof(Foo);
// include
expect([1,2,3]).to.include(2);
expect('foobar').to.contain('foo');
expect({ foo: 'bar', hello: 'universe' }).to.include.keys('foo');
// empty
expect([]).to.be.empty;
expect('').to.be.empty;
expect({}).to.be.empty;
// match
expect('foobar').to.match(/^foo/);

基本上,expect断言的写法都是一样的。头部是expect方法,尾部是断言方法,比如equal、a/an、ok、match等。两者之间使用to或to.be连接。对于结果值的判断用to.be链接,而对于结果是函数的判断通过to链接。
有了测试脚本以后,就可以用Mocha运行它。

1
2
3
4
5
6
$ mocha add.test.js
加法函数的测试
✓ 1 加 1 应该等于 2
1 passing (8ms)

上面的运行结果表示,测试脚本通过了测试,一共只有1个测试用例,耗时是8毫秒。Mocha默认运行test第一层子目录里面的测试脚本。所以,一般都会把测试脚本放在test目录里面,然后执行mocha就不需要参数了。为了改变默认运行test第一层子目录这种行为,就必须加上–recursive参数,这时test子目录下面所有的测试用例,不管在哪一层都会执行。mocha目录同样支持通配符,如下:

1
2
3
4
5
$ mocha --recursive
//通配符
$ mocha spec/{my,awesome}.js
$ mocha test/unit/*.js
$ mocha test/{,**/}*.{js,jsx}

关于mocha其他的参数,可以查看 mocha -h
详细参考阮老师文章: http://www.ruanyifeng.com/blog/2015/12/a-mocha-tutorial-of-examples.html

es6编写测试脚本

测试用例可以采用es6来编写,如下:

1
2
3
4
5
6
7
8
9
10
import add from '../src/add.js';
import chai from 'chai';
let expect = chai.expect;
describe('加法函数的测试', function() {
it('1 加 1 应该等于 2', function() {
expect(add(1, 1)).to.be.equal(2);
});
});

执行测试用例之前需要采用babel转义es6,

1
$ npm install babel-core babel-preset-es2015 --save-dev

然后,在项目目录下面,新建一个.babelrc配置文件。

1
2
3
{
"presets": [ "es2015" ]
}

最后,使用–compilers参数指定测试脚本的转码器。

1
$ ../node_modules/mocha/bin/mocha --compilers js:babel-core/register

上面代码中,–compilers参数后面紧跟一个用冒号分隔的字符串,冒号左边是文件的后缀名,右边是用来处理这一类文件的模块名。上面代码表示,运行测试之前,先用babel-core/register模块,处理一下.js文件。由于这里的转码器安装在项目内,所以要使用项目内安装的Mocha;如果转码器安装在全局,就可以使用全局的Mocha。
下面是另外一个例子,使用Mocha测试CoffeeScript脚本。测试之前,先将.coffee文件转成.js文件。

1
$ mocha --compilers coffee:coffee-script/register

注意,Babel默认不会对Iterator、Generator、Promise、Map、Set等全局对象,以及一些全局对象的方法(比如Object.assign)转码。如果你想要对这些对象转码,就要安装babel-polyfill。

1
$ npm install babel-polyfill --save

然后,在你的脚本头部加上一行。

1
import 'babel-polyfill'

关于异步测试用例

Mocha默认每个测试用例最多执行2000毫秒,如果到时没有得到结果,就报错。对于涉及异步操作的测试用例,这个时间往往是不够的,需要用-t或–timeout参数指定超时门槛。

1
2
3
4
5
6
7
8
9
it('测试应该5000毫秒后结束', function(done) {
var x = true;
var f = function() {
x = false;
expect(x).to.be.not.ok;
done(); // 通知Mocha测试结束
};
setTimeout(f, 4000);
});

上面的测试用例,需要4000毫秒之后,才有运行结果。所以,需要用-t或–timeout参数,改变默认的超时设置。

1
2
3
4
5
6
7
8
9
10
11
12
13
$ mocha -t 5000 timeout.test.js
也可以在测试用例中动态制定:
it('测试应该5000毫秒后结束', function(done) {
this.timeout(5000);
var x = true;
var f = function() {
x = false;
expect(x).to.be.not.ok;
done(); // 通知Mocha测试结束
};
setTimeout(f, 4000);
});

上面命令将测试的超时时限指定为5000毫秒。另外,上面的测试用例里面,有一个done函数。it块执行的时候,传入一个done参数,当测试结束的时候,必须显式调用这个函数,告诉Mocha测试结束了。否则,Mocha就无法知道,测试是否结束,会一直等到超时报错。你可以把这行删除试试看。
详细参考阮老师文章: http://www.ruanyifeng.com/blog/2015/12/a-mocha-tutorial-of-examples.html

测试用例的钩子

Mocha在describe块之中,提供测试用例的四个钩子:before()、after()、beforeEach()和afterEach()。它们会在指定时间执行。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
describe('hooks', function() {
before(function() {
// 在本区块的所有测试用例之前执行
});
after(function() {
// 在本区块的所有测试用例之后执行
});
beforeEach(function() {
// 在本区块的每个测试用例之前执行
});
afterEach(function() {
// 在本区块的每个测试用例之后执行
});
// test cases
});

详细参考阮老师文章: http://www.ruanyifeng.com/blog/2015/12/a-mocha-tutorial-of-examples.html
附上阮老师的案例:https://github.com/ruanyf/mocha-demos

mocha API:https://mochajs.org/#getting-started

mocha bugs

在使用mocha在浏览器测试中遇到过一些问题,有些很难解决,比如:

1
script error (:0) , uncaught error

上面这个在写异步测试用例,调用done方法后会报错,不一定都会,我遇到的是会报错,排查了很久,发现的原因是我写的测试用例是基于自己定义的 define函数和require函数来写的,在执行异步操作的时候,调用done方法的时候这个测试用例已经执行过了,导致调用done的时候,对应test为null,可以在这里写个debugger看下:

1
2
3
4
5
self.currentRunnable = self.test;
self.runTest(function (err) {
debugger
test = self.test;
if (err) {

很是奇怪,分析了半天没找到原因,想想可能是我用的define和require的问题,于是把测试用例去掉define定义,直接用es6模块来写,然后运行时正常的,

chai

上面提到过,chai主要是一个断言库,用来实现断言的。chai提供了expect和should两种BDD风格的断言函数。

expect和should是BDD风格的,二者使用相同的链式语言来组织断言,但不同在于他们初始化断言的方式:expect使用构造函数来创建断言对象实例,而should通过为Object.prototype新增方法来实现断言(所以should不支持IE);expect直接指向chai.expect,而should则是chai.should()。
个人比较建议使用expect,should不仅不兼容IE,在某些情况下还需要改变断言方式来填坑。

chai API: http://chaijs.com/api/bdd/#
中文chai API: http://www.jianshu.com/p/f200a75a15d2

nightWatch

想起了守护长城的守夜人。官网:http://nightwatchjs.org/
Nightwatch是一套新近问世的基于Node.js的验收测试框架,使用Selenium WebDriver API以将Web应用测试自动化。它提供了简单的语法,支持使用JavaScript和CSS选择器,来编写运行在Selenium服务器上的端到端测试。

不同于行为驱动测试(BDD)和单元测试独立运行并使用模拟/存根,端到端测试将试着尽可能从用户的视角,对真实系统的访问行为进行仿真。对Web应用来说,这意味着需要打开浏览器、加载页面、运行JavaScript,以及进行与DOM交互等操作。Nightwatch尝试着使用语法糖(syntax sugar)来实现这一目标:

1
2
3
4
5
6
7
8
9
10
11
this.demoTestGoogle = function (browser) {
browser
.url(“http://www.google.com”)
.waitForElementVisible('body', 1000)
.setValue('input[type=text]', 'nightwatch')
.waitForElementVisible('button[name=btnG]', 1000)
.click('button[name=btnG]')
.pause(1000)
.assert.containsText('#main', 'The Night Watch')
.end();
};

目前,Selenium是JavaScript的世界里验收测试方面最流行的工具之一,类似的还有PhantomJS。二者都有其独到的方法:Selenium使用其WebDriver API,而PhantomJS使用无界面的WebKit浏览器。它们都是非常成熟的工具,都具有强大的社区支持。它们与Nightwatch之间最大的不同,主要是在于语法的简易度以及对持续集成的支持。与Nightwatch相比,Selenium和PhantomJS都拥有更加冗长的语法,这会让编码变得更庞大,而且不支持从命令行中进行开箱即用的持续集成(JUnit XML或其他标准输出)。

使用方法

安装:

1
$ npm install [-g] nightwatch

配置:
默认读取当前目录下的nightwatch.json文件,内容如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
//nightwatch.json
{
"src_folders" : ["tests"],
"output_folder" : "reports",
"custom_commands_path" : "",
"custom_assertions_path" : "",
"page_objects_path" : "",
"globals_path" : "",
"selenium" : {
"start_process" : false,
"server_path" : "",
"log_path" : "",
"port" : 4444,
"cli_args" : {
"webdriver.chrome.driver" : "",
"webdriver.gecko.driver" : "",
"webdriver.edge.driver" : ""
}
},
"test_settings" : {
"default" : {
"launch_url" : "http://localhost",
"selenium_port" : 4444,
"selenium_host" : "localhost",
"silent": true,
"screenshots" : {
"enabled" : false,
"path" : ""
},
"desiredCapabilities": {
"browserName": "firefox",
"marionette": true
}
},
"chrome" : {
"desiredCapabilities": {
"browserName": "chrome"
}
},
"edge" : {
"desiredCapabilities": {
"browserName": "MicrosoftEdge"
}
}
}
}

nightmare

nightmare现在也很好用,nightmare官网: http://www.nightmarejs.org/
A high-level browser automation library,基于浏览器自动化测试的API, 与nightwatch不同的是,nightmare采用的是基于 electron 的 headless 浏览器,封装提供了许多牛逼的API,包括导入js和css代码。但是貌似导入JS代码只能限于无模块(无AMD/CMD/UMD)的普通JS代码,否则js会报错,报错后的内容统统失效。导入的JS代码如果有错误,后面的错误都会被屏蔽掉。所以采用的方法是通过JS来加载JS代码。

1
2
3
4
5
6
7
8
9
function loadScript(url, cb) {
var script = document.createElement('script');
script.src = url;
script.onload = function () {
cb && cb()
};
document.head.appendChild(script);
}

谢谢!

转载请注明出处://fed123.oss-ap-southeast-2.aliyuncs.com/2017/03/05/2017_doTest/
请扫描左侧二维码,关注读书学技术服务号!每周更新学习文章以及技术书籍推荐哦!
欢迎关注皓眸学问公众号(扫描左侧二维码),每天好文、新技术!任何学习疑问或者工作问题都可以给我留言、互动。T_T 皓眸大前端开发学习 T_T

fed123版权所有,转载请保留出处:前端123学堂 » 前端测试方法+工具

赞 (0) 打赏

评论 0

  • 昵称 (必填)
  • 邮箱 (必填)
  • 网址

如果对您有帮助,别忘了打赏一下宝宝哦!

支付宝扫一扫打赏

微信扫一扫打赏