mocha + chai + supertest 测试 node server

2018-07-16
nodejs
5182

要在Nodejs中写单元测试的话,你需要知道用什么测试框架,怎么测试异步函数,怎么测试私有方法,怎么模拟测试环境,怎么测试依赖HTTP协议的web应用,需要了解TDD和BDD,还有需要提供测试的覆盖率。

测试技术栈

  • mocha
  • chai
  • supertest

Mocha 是一个功能丰富的Javascript测试框架,它能运行在Node.js和浏览器中,支持BDD、TDD、QUnit、Exports式的测试。Mocha本身不带断言库,所以必须先引入断言库, 官网

Chai 是一个BDD/TDD的断言库,官网

所谓"断言",就是判断源码的实际执行结果与预期结果是否一致,如果不一致就抛出一个错误。

Chai提供expectshould两个BDD风格的API,二者使用相同的链式语言来组织断言,但不同在于他们初始化断言的方式:expect使用构造函数来创建断言对象实例,而should通过为Object.prototype新增方法来实现断言(所以should不支持IE);expect直接指向chai.expect,而should则是chai.should()

// 引入断言库
var chai = require('chai') ,
    expect = chai.expect ,
    should = chai.should();

// 相等或不相等
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/);

supertest 专门用于 http 请求的断言

针对函数的测试

待测函数add.js

function add (a, b) {
    return a + b;
}

module.exports = add;

测试普通函数test.js

const expect = require('chai').expect; // 引入chai
const add = require('./add.js'); // 引入add.js

describe('test add function', function () {
    it('1 + 2 = 3', function () {
        expect(add(1 + 2)).to.be.equal(3);
    })
})

之后运行,得到测试结果。

mocha test.js

针对异步函数测试

对于异步执行的函数,外部不能直接知道什么时候函数执行完了。因此,mocha框架会传入一个callback (done),当异步调用完成之后,执行这个callback,告诉mocha这个函数执行完了。看个例子。

decribe('asyn test', function () {
    it('asyn test', function (done) {
        ...
        done();
    })
})

针对接口测试

测试get请求

const request = require('supertest');
const expect = require('chai').expect;
const app = require('../app.js'); // 这里是express框架自动生成的app.js

describe('test get request', function () {
    it ('get a image', function (done) {
        request(app)
          .get('/')
          .expect(200, done);
    })
});

测试时不用启动服务器,supertest会自动去执行代码,可以在指定路由下面打log,看是否执行。写好测试代码之后,执行

mocha ./test/test.js

post请求

只写it函数里面的内容。

request(app)
  .post('/login')
  .send(data)  // send a json data
  .expect(200)
  .end(function (req, res) {
      expect(res.status).to.be.equal('ok'); // 请求完成测试请求内容是否符合预期
    done();
  })

要设置cookie需要用到supertest的agent模拟客户端

decribe('set cookie', function () {
    it ('set cookie', functin (done) {
        const agent = request.agent(app); // agent 代替request,其余不变
        agent
           .get('/')
           .set('Cookie', ['token=fdjasklfdsla']) // set cookie
           .expect(200, done)
    })
})

change host

supertest 默认host是127.0.0.1,对于一些需要特定host访问的接口,可以这样修改host

agent.set('host', 'HOST')

设置超时时间

supertest 默认请求超时时间是2000ms,很多异步请求都没有完成就被判死刑了。所以需要手动设置超时时间。

// 在代码中设置
// 在代码中设置,保证不同接口的差异性
agent.timeout(5000);

// 在执行时设置参数-t 或者 -timeout
// 执行行时一次性设置,少写代码,但是不推荐
mocha -t 5000 test.js