编写单元测试
单元测试在Nightwatch 0.9版本已经得到了改进。现在在Nightwatch上编写的单元测试也与Mocha的导出接口完全兼容,因此你可以使用任何一个测试运行程序。事实上,所有Nightwatch单元测试都被重写了这样可以用Nightwatch或者Mocha来运行了。
为了向后兼容的原因,为了利用改进的单元测试支持,你需要在测试setting中设置
compatible_testcase_support=true
在0.9版本之前编写的单元测试仍然可以继续工作,但是建议升级到最新版本的Nightwatch。
禁用automatic selenium session
Nightwatch会企图自动尝试连接到指定的selenium服务器,并创建一个会话。当运行单元测试时,需要在selenium设置中将start_session属性设置为false。
Assertion 框架
从0.9版本开始,在对单元测试的改进支持中,客户端对象不再作为测试的参数传递。现在传递的惟一参数是用于异步测试的done的回调。
你可以使用任何你喜欢的断言框架。比如Chai.js非常好,而且非常灵活。我们在Nightwatch单元测试中使用内部的Node.js assert。
你仍然可以在你的测试中通过这个引用client对象,比如 this.client
例子,这是Nightwatch模块中utils.js的一个子集:
var assert = require('assert');
var common = require('../../common.js');
var Utils = common.require('util/utils.js');
module.exports = {
'test Utils' : {
testFormatElapsedTime : function() {
var resultMs = Utils.formatElapsedTime(999);
assert.equal(resultMs, '999ms');
var resultSec = Utils.formatElapsedTime(1999);
assert.equal(resultSec, '1.999s');
var resultMin = Utils.formatElapsedTime(122299, true);
assert.equal(resultMin, '2m 2s / 122299ms');
},
testMakeFnAsync : function() {
function asyncFn(cb) {
cb();
}
function syncFn() {}
var convertedFn = Utils.makeFnAsync(1, syncFn);
var called = false;
convertedFn(function() {
called = true;
});
assert.equal(Utils.makeFnAsync(1, asyncFn), asyncFn);
assert.ok(called);
}
}
};
异步单元测试
测试函数的参数done是可选的回调函数,它表示测试完成了。如果存在,则必须在异步操作结束时调用回调函数。
例子,这个单元测试检查如果Nightwatch在一段时间内不调用done的回调(10毫秒),是否会抛出一个错误。
module.exports = {
var path = require('path');
var assert = require('assert');
var common = require('../../common.js');
var CommandGlobals = require('../../lib/globals/commands.js');
var Runner = common.require('runner/run.js');
module.exports = {
'testRunner': {
before: function (done) {
CommandGlobals.beforeEach.call(this, done);
},
after: function (done) {
CommandGlobals.afterEach.call(this, done);
},
beforeEach: function () {
process.removeAllListeners('exit');
process.removeAllListeners('uncaughtException');
},
'test async unit test with timeout error': function (done) {
var testsPath = path.join(__dirname, '../../asynchookstests/unittest-async-timeout.js');
var globals = {
calls : 0,
asyncHookTimeout: 10
};
process.on('uncaughtException', function (err) {
assert.ok(err instanceof Error);
assert.equal(err.message, 'done() callback timeout of 10 ms was reached while executing "demoTest". ' +
'Make sure to call the done() callback when the operation finishes.');
done();
});
var runner = new Runner([testsPath], {
seleniumPort: 10195,
silent: true,
output: false,
persist_globals : true,
globals: globals,
compatible_testcase_support : true
}, {
output_folder : false,
start_session : false
});
runner.run().catch(function(err) {
done(err);
});
}
}
};
};
完整的test suit可以在GitHub上查看:https://github.com/nightwatchjs/nightwatch/tree/master/test/src/runner/testRunner.js
运行Nightwatch单元测试
为了了解如何使用Nightwatch代码运行单元测试,你可以转到GitHub页面,克隆项目,并按照测试说明来运行。
你也可以查看Nightwatch自己的完整test suit,例如:https://github.com/nightwatchjs/nightwatch/tree/master/test/src
以下是运行它们所需的配置:
{
"src_folders" : ["./test/src"],
"selenium" : {
"start_process" : false,
"start_session" : false
},
"test_settings" : {
"default" : {
"filter" : "*/.js",
"compatible_testcase_support" : true
}
}
}
使用组合配置
下面是如何将E2E测试和单元测试结合在一起的一个示例,他们都配置在nightwatch.json文件中。注意使用exclude和filter属性。
一个空的exclude意味着我们想要重置它的值,这时候只依赖于filter。
{
"src_folders" : ["./examples/tests", "./examples/unittests"],
"output_folder" : "./examples/reports",
"selenium" : {
"start_process" : true,
"server_path" : "./bin/selenium-server-standalone.jar",
"log_path" : "",
"host" : "127.0.0.1",
"port" : 4444,
"cli_args" : {
"webdriver.chrome.driver" : "",
"webdriver.ie.driver" : ""
}
},
"test_settings" : {
"default" : {
"launch_url" : "http://localhost",
"selenium_port" : 4444,
"selenium_host" : "localhost",
"silent": true,
"screenshots" : {
"enabled" : false,
"path" : ""
},
"desiredCapabilities": {
"browserName": "firefox",
"javascriptEnabled": true,
"acceptSslCerts": true
},
"exclude" : "./examples/unittests/*"
},
"unittests" : {
"selenium" : {
"start_process" : false,
"start_session" : false
},
"filter" : "./examples/unittests/*",
"exclude" : ""
}
}
}
代码覆盖率
目前,Nightwatch没有提供一个覆盖率reporter,计划在未来的版本里实现。同时,你可以编写一个定制的报告,它将输出覆盖率数据。详情参看custom repoter section和Mocha HTMLCov 关于reporter应该看起来是什么样。