最近在负责一个基于nodejs的应用,在很多方面都经历了一个从无到有的过程,测试也是如此。刚开始时,代码都写不好,更别提测试了,那时测试为0。经历过一段时间后,尤其是看到 npm 上优秀的库的测试覆盖率都在100%时,痛下决心开始学习 nodejs 的测试, 目前这个应用的测试覆盖率在90% 。这就是我的从0到90。剩下的10,还有很长的路,且待下回分解。 写在前面的对于开发者,测试的重要性毋庸置疑, 所谓”无测试不上线“,”无测试不重构“等。但在实践的过程中,测试总是有这样的那样的问题,随便列举下:
一个好的测试一千个人眼中有至少二千种测试理念或方法,很难定义什么是一种好的测试。在团队一直负责测试的推进,我们的理念很简单,包括以下几个原则:
一个好的测试,最重要的衡量标准就是测了多少(覆盖率),75%是最低的标准。这个标准对java来说基本可行,但对nodejs不太适用,javascript是弱类型的、动态语言,没有编译阶段,很多错误只能在运行时才会被发现,所以需要更高的覆盖率,最好是100%,目前个人的标准是90% 。
每一个测试用例,无论在任何环境下,都应该可以反复执行,并产生相同的结果。只有这样,才能够相任你的测试,进而发现真正的bug。这也是集成测试最低要求。
一个测试用例只测试代码的某一方面,如一个分支,且不强依赖某些特定的环境或条件。
无论是单个测试用例,还是集成测试,必须要保证测试执行足够的快。 测什么测试测什么主要依据具体的需求、业务、成本、语言等,但也有一定的共性,单元测试准则 给出了一些准则可供参考,这里不再讨论。 怎么测又是一个非常大的话题,本文仅从个人角度给出nodejs测试的工具及方法。 概述框架Nodejs 测试框架众多,目前使用最广的是Mocha。本文详细说明下 Mocha, 并简要介绍几种其它框架。本文的示例,如无特别说明,都是基于Mocha. MochaA simple, flexible, fun JavaScript test framework for node.js and the browser. Mocha 是一个功能丰富的Javascript测试框架,它能运行在Node.js和浏览器中,支持BDD、TDD式的测试。 快速开始
npm install -g mocha
var assert = require('chai').assert;
describe('Array', function() {
describe('#indexOf()', function () {
it('should return -1 when the value is not present', function () {
assert.equal(-1, [1,2,3].indexOf(5));
assert.equal(-1, [1,2,3].indexOf(0));
});
});
});
$ mocha
输出结果如下: .
1 test complete (1ms)
使用断言Mocha 允许你使用任何你想用的断言库,包括:
钩子 HooksMocha 提供了 describe('hooks', function() {
before(function() {
// runs before all tests in this block
})
after(function(){
// runs after all tests in this block
})
beforeEach(function(){
// runs before each test in this block
})
afterEach(function(){
// runs after each test in this block
})
// test cases
})
专用测试 或 跳过测试专用测试允许只测试指定的测试集或用例,只需在测试集或用例前加 describe('Array', function(){
describe.only('#indexOf()', function(){
...
})
})
跳过类似于 junit 的 describe('Array', function(){
describe.skip('#indexOf()', function(){
...
})
})
编辑器插件除了使用 Mocha 提供的命令行外,还可以使用 编辑器插件 运行,目前支持了:
以JetBrains为例,JetBrain 为其 IDE 套件(IntelliJ IDEA, WebStorm等)提供了 NodeJS, 可以直接运行或调试 mocha 测试用例。基本步骤:
其它以下列举几个基于 nodejs 的测试框架或工具,它们可用于 nodejs 或 浏览器端javascript 代码的测试,不在本文讨论范围,详见官方文档。 JasmineA Behavior Driven Development JavaScript testing framework
更多见 官方文档. Karma RunnerTo bring a productive testing environment to developers
更多见 官方文档. 工具mocha 提供了测试的基本框架,在特定的场景下的测试还需要其它工具做以辅助,这个列举几个常用的工具。 SuperTestSuperTest 提供对 HTTP 测试的高度抽象, 极大地简化了基于 HTTP 的测试。
安装$ npm install supertest --save-dev
使用示例
var request = require('supertest');
describe('GET /user', function() {
it('respond with json', function(done) {
request(app)
.get('/user')
.set('Accept', 'application/json')
.expect('Content-Type', /json/)
.expect(200, done);
});
});
request(app)
.post('/')
.field('name', 'my awesome avatar')
.attach('avatar', 'test/fixtures/homeboy.jpg')
// ..
describe('GET /user', function() {
it('user.name should be an case-insensitive match for 'tobi'', function(done) {
request(app)
.get('/user')
.set('Accept', 'application/json')
.expect(function(res) {
res.body.id = 'some fixed id';
res.body.name = res.body.name.toUpperCase();
})
.expect(200, {
id: 'some fixed id',
name: 'TOBI'
}, done);
});
});
更多见 文档 Istanbul代码覆盖(Code coverage)是软件测试中的一种度量,描述程式中源代码被测试的比例和程度,所得比例称为代码覆盖率。它有四个测量维度:
Istanbul 是 JavaScript 语言最流行的代码覆盖率工具。 快速开始
$ npm install -g istanbul
最简单的方式: $ cd /path/to/your/source/root
$ istanbul cover test.js
输出运行结果: ..
test/app/util/result.test.js
should static create
should be success
should be static success
should be error
should be static error
299 passing (13s)
[mochawesome] Report saved to /opt/source/node_modules/.mochawesome-reports/index.html
=============================== Coverage summary ===============================
Statements : 92.9% ( 1505/1620 )
Branches : 85.42% ( 410/480 )
Functions : 94.33% ( 133/141 )
Lines : 93.01% ( 1504/1617 )
================================================================================
Done
这条命令同时还生成了一个 模式常见的测试模式包括TDD, BDD。 TDD (Test Driven Development)测试驱动开发是敏捷开发中的一项核心实践和技术,也是一种设计方法论。TDD的原理是在开发功能代码之前,先编写单元测试用例代码,测试代码确定需要编写什么产品代码。TDD的基本思路就是通过测试来推动整个开发的进行,但测试驱动开发并不只是单纯的测试工作,而是把需求分析,设计,质量控制量化的过程。整体流程如下: 以一个阶乘的小程序为例。先写出的测试用例,如下所示。此时运行肯定会报错,因为被测试的程序还没有写。 var assert = require('assert'),
factorial = require('../index');
suite('Test', function (){
suite('#factorial()', function (){
test('equals 1 for sets of zero length', function (){
assert.equal(1, factorial(0));
});
test('equals 1 for sets of length one', function (){
assert.equal(1, factorial(1));
});
test('equals 2 for sets of length two', function (){
assert.equal(2, factorial(2));
});
test('equals 6 for sets of length three', function (){
assert.equal(6, factorial(3));
});
});
});
开始写阶乘的逻辑,如下所示。 module.exports = function (n) {
if (n < 0) return NaN;
if (n === 0) return 1;
return n * factorial(n - 1);
};
此时再运行之前的测试用例,看其是否通过,如果全部通过则表示开发完成,如不通过则反复修改被测试的逻辑,直到全部的通过为止。 BDD (Behavior Driven Development)行为驱动开发是一种敏捷软件开发的技术,它鼓励软件项目中的开发者、QA和非技术人员或商业参与者之间的协作。主要是从用户的需求出发,强调系统行为。其最显著的特征是,通过编写行为和规格说明来驱动软件开发。行为和规格说明看上去与测试十分相似,但它们之前还是有显著的不同。 还是以上面的阶乘为例,BDD模式的测试用例如下: var assert = require('assert'),
factorial = require('../index');
describe('Test', function (){
before(function(){
// Stuff to do before the tests, like imports, what not
});
describe('#factorial()', function (){
it('should return 1 when given 0', function (){
factorial(0).should.equal(1);
});
it('should return 1 when given 1', function (){
factorial(1).should.equal(1);
});
it('should return 2 when given 2', function (){
factorial(2).should.equal(2);
});
it('should return 6 when given 3', function (){
factorial(3).should.equal(6);
});
});
after(function () {
// Anything after the tests have finished
});
});
从示例上看,BDD的测试用例与TDD最大的不同在于其措辞,BDD读起来更像是一个句子。因此BDD的测试用例可作为开发者、QA和非技术人员或商业参与者之间的协同工具,对开发者来说,如果你可以非常流畅地读测试用例,自然能够写出更好、更全面的测试。 TDD vs BDDTDD和BDD本质和目标都是一致的。只是在实施方法上,进行了不同的探讨来完善整个敏捷开发的体系。TDD的迭代反复验证是敏捷开发的保障,但没有明确如何根据设计产生测试,并保障测试用例的质量,而BDD倡导大家都用简洁的自然语言描述系统行为的理念,恰好弥补了测试用例(即系统行为)的准确性。 几乎所有基于Nodejs的库或应用都选择了BDD, 至于为什么,我还没有搞明白。 断言目前比较流行的断言库包括:
这些断言库除了风格上略有不同外,实现在功能几乎完全一致,可根据个人喜好或应用需求选择。 |
|