作为过来人,首先想说的是:不要怕!

刚从前端转来做Node的,从来没接触过单元测试,一听这个名词就觉得高大上。加上周围一些前端儿也基本没有接触过单元测试,总把单元测试看得比较遥远,中文教程也点到即止并有点过分重视命令行参数的讲解,让我迟迟不敢轻易入坑。

然而,当项目确实希望用到单元测试的时候,我决定抛开内心的恐惧,硬着头皮认认真真地读英文版的Mocha和chai Assert文档,发现,真的不过如此而已!远远没有想象中的难,Hour级入门。

现在,我有一种感觉:不跑单元测试会让我感到恐慌。。。

这一次又给了我深刻的教训:接触一个新技术的时候,不要慌,不要害怕,不过分依赖过来人的看法,不亲自实践又怎知难易呢?

罗里吧嗦了一大堆,现在开始步入正题。。。

一. 单元测试

单元测试分为两种:

  • TDD:Test-Driven Development,测试驱动开发,注重输出结果。
  • BDD:Behavior Driven Development,行为驱动开发,注重测试逻辑。

对于TDD、BDD的区别可查看:关于TDD、BDD和DDD的一些看法

对于单元测试,推荐查看【译】每个单元测试必须回答的 5 个问题

mocha默认的模式是BDD。

二. Mocha介绍

在Node.js中,目前比较流行的单元测试组合是mocha + chai。mocha是一个测试框架,chai是一个断言库,所以合称”抹茶”。

断言库类型有:jasmineshould.jschaiassert。哪个更好主要看团队和项目需要吧,个人喜欢chai断言库的assert风格,更接近原生也更人性化。

Mocha主要特性有:

  • 支持异步的测似用例,如Promise;
  • 支持代码覆盖率coverage测试报告;
  • 支持配置不同的测试(如断言库);
  • … …

本文使用的是:Mocha + chai(assert风格)

安装如下

npm install mocha -g
npm install mocha
npm install chai

跑Mocha测试的命令

mocha [debug] [options] [files]

如:
mocha --recursive test/

二. Mocha的三个基本方法:

Mocha有三个基本方法:

describe(moduleName, function)

describe是可嵌套的,描述测试用例是否正确。

describe('测试模块的描述', function() {
  // ....
});

it(info, function)

info为描述性说明。一个it对应一个单元测试用例。

describe('单元测试的描述,一般写明用途和返回值', function() {
  // ....
});

assert.equal(exp1, exp2)

mocha的断言语句,判断exp1是否等于exp2。

三. Mocha的异步代码测试:

done

一个it里面只有一个done。

done标识回调的最深处,也是嵌套回调函数的末端。

备注:在mocha v3.x版本,Promise回调不需要使用 done 来标识回调最深处,并且在Promise回调中是用done回报错。

describe('User', function() {
  describe('#save()', function() {
    it('should save without error', function(done) {
      var user = new User('Luna');
      user.save(done);
    });
  });
});

四. Test Hooks方法:

before()after()beforeEach()afterEach() 是基于BDD风格提出的。用于预处理和test后的处理。

Test Hooks方法的几个注意点:

  • beforeEach会对当前describe下的所有子case生效;
  • before和after的代码没有特殊顺序要求;
  • 同一个describe下的执行顺序为before、beforeEach、afterEach、after;
  • 当一个it有多个before的时候,执行顺序是从最外围的describe的before开始,其他同理。
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
});

Hooks的三种写法:

beforeEach(function() {
});

beforeEach(function nameFun() {
});

beforeEach("some description", function() {
});

五. only()、skip()函数

describe块和it块都允许调用only()skip()方法。

only()方法表示在当前的父describe块下,只执行该单元的测试。

skip()方法表示在当前的父describe块下,跳过不执行该单元的测试。

当在一个describe块下,同时存在only()skip()方法,则只执行.only()方法。

describe('Array', function() {
  describe.only('父describe块下只执行该测试单元', () => {
    it.skip('跳过的测试单元', () => { //... });
  });
  describe('不执行', () => { //... });
});

六. mocha 常用命令参数

–recursive 遍历子目录下的全部文件

Mocha默认运行/test子目录里面的测试脚本。

Mocha默认只执行/test子目录下第一层的测试用例。

所以,应加上–recursive参数,使全部子目录下的测试用例都能被执行。

mocha --recursive

-u tdd 执行TDD模式

mocha默认的模式是BDD,要想执行TDD的test时需要加上参数,如:

mocha -u tdd test.js

–watch, -w 监听脚本变化

--watch参数用来监视指定的测试脚本。当脚本发生变化,就会自动运行mocha。

mocha --watch

–bail, -b

只要有一个测试用例没有通过,就会停止执行后面的测试用例。

-timeout, -t 指定超时门槛

Mocha默认每个测试用例最多执行2000毫秒。如果2000毫秒后还没有执行完成,则报错。-t可执行超时门槛。

mocha -t 5000 test.js

使用nobe通配符适配文件

mocha spec/{my,awesome}.js
mocha test/unit/*.js
mocha 'test/**/*.@(js|jsx)'

七. chai库

我个人比较喜欢assert风格。具体可查看文档:http://chaijs.com/api/assert/

其实最常用的API也就那几个:

  • .equal(actual, expected, [message])
  • .deepeEqual(actual, expected, [message])
  • .isOk(object, [message])
  • .isTrue(value, [message])
  • .include(haystack, needle, [message])
  • … …

八. 参考

  1. Node.js 单元测试:我要写测试:http://taobaofed.org/blog/2015/12/10/nodejs-unit-tests/
  2. 【译】每个单元测试必须回答的 5 个问题:https://www.h5jun.com/post/5-questions-every-unit-test-must-answer.html
  3. 测试框架 Mocha 实例教程:http://www.ruanyifeng.com/blog/2015/12/a-mocha-tutorial-of-examples.html
本文作者:子匠_Zijor,转载请注明出处:http://www.dengzhr.com/node-js/1282