JavaScript 测试基础,TDD、BDD、Benchmark

目录

    • 测试框架
    • TDD
    • BDD
    • Benchmark
      • 使用场景
      • 结果报告示例
      • 示例代码

原则:谁开发,谁测试。

注意: 原则上应该先写测试,再进行编码;如果需求时间紧,可以先进行功能实现,但务必后续维护时候将测试代码补充完善。

BDD(优先)+TDD(完全代码覆盖)

测试框架

常见的组合:

  • ES5: mocha + istanbul
  • ES6: ava + nyc

TDD

Test Driven Development,(单元)测试驱动开发。

特点:

  1. 直接引用对应源码,执行方法进行测试;
  2. 测试用例须设计完整,把所有分支都 Cover 到。

示例:

describe('Lib Common', function () {
  'use strict';
  it('isEmpty', function () {
    // isObject
    isEmpty({}).should.be.equal(true);
    isEmpty([]).should.be.equal(true);
    isEmpty({ a: 1 }).should.be.equal(false);
    isEmpty([1, 2]).should.be.equal(false);
    // isString
    isEmpty('').should.be.equal(true);
    isEmpty('sth').should.be.equal(false);
    // isNumber
    isEmpty(0).should.be.equal(true);
    isEmpty(0.1).should.be.equal(false);
    // null and undefined
    isEmpty(null).should.be.equal(true);
    isEmpty(undefined).should.be.equal(true);
    // boolean
    isEmpty(false).should.be.equal(true);
    isEmpty(true).should.be.equal(false);
    // 最后一行false
    isEmpty(isEmpty).should.be.equal(false);
  });
  it('md5/sha1', function () {
    md5('sth').should.equal('7c8db9682ee40fd2f3e5d9e71034b717');
    sha1('sth').should.equal('dec981e3bbb165d021029c42291faf06f59827c1');
  });
  it('authcode', function () {
    authcode(authcode('test'), 'DECODE').should.be.equal('test');
    authcode(authcode('test', 'ENCODE', 'key'), 'DECODE', 'key').should.be.equal('test');
    authcode('c008AsZqmGL8VuEVpZKVlbPwXzSsCZ+YX5K5CAGpMMqn', 'DECODE').should.be.equal('');
  });
});

BDD

Behavior Driven Development,行为驱动开发。

特点:

  1. 运行系统,模拟用户请求进行访问;
  2. 行为分析要完整,要将可能所有结果覆盖。

示例:

/* 测试路由 */
app.get('/test/model/mysql/init/ok', function (req, res) {
  'use strict';
  return db
    .opensips('v1/subscriber')
    .then(function () {
      res.send(200, 'ok');
    })
    .catch(function (err) {
      logger('routes/test/model/mysql/ok', err);
      res.send(403, 'fail');
    });
});

app.get('/test/model/mysql/init/fail', function (req, res) {
  'use strict';
  return db
    .opensips('test/notExisted')
    .then(function () {
      res.send(200, 'OK');
    })
    .catch(function () {
      res.send(200, 'fail');
    });
});

/* 测试脚本 */
describe('Demo', function () {
  'use strict';
  it('404 not found', function (next) {
    request(app)
      .get('/sth/not/exist')
      .set('Accept', 'text/plain')
      .expect(200)
      .end(function (err, res) {
        if (err) {
          throw err;
        }
        should(res.body.status).be.equal(0);
        next();
      });
  });
  it('403 not allowed', function (next) {
    request(app)
      .get('/v2/basic/mqtt')
      .set('Accept', 'text/plain')
      .expect(200)
      .end(function (err, res) {
        if (err) {
          throw err;
        }
        should(res.body.status).be.equal(0);
        next();
      });
  });
  it('Init opensips/subscriber Should be OK', function (next) {
    request(app)
      .get('/test/model/mysql/init/ok')
      .set('Accept', 'text/plain')
      .expect(200)
      .expect('ok')
      .end(function (err) {
        if (err) {
          //console.log(res.body);
          throw err;
        }
        next();
      });
  });
  it('Init test/subscriber Should be FAILED', function (next) {
    request(app)
      .get('/test/model/mysql/init/fail')
      .set('Accept', 'text/plain')
      .expect(200)
      .expect('fail')
      .end(function (err) {
        if (err) {
          //console.log(res.body);
          throw err;
        }
        next();
      });
  });
});

ES6 下的 BDD 测试示例对比:

import { test, server, assert } from './_import';
let location;
test.before(async () => {
  const response = await server.inject({
    method: 'POST',
    url: '/login',
    payload: {
      username: 'willin',
      password: 'PASSWORD'
    }
  });
  location = response.headers.location;
});

test('GET / 302', async () => {
  const response = await server.inject({
    method: 'GET',
    url: '/'
  });
  assert.equal(response.statusCode, 302);
});

test('GET /login 200', async () => {
  const response = await server.inject({
    method: 'GET',
    url: '/login'
  });
  assert.equal(response.statusCode, 200);
});

test('POST /login 302', async () => {
  const response = await server.inject({
    method: 'POST',
    url: '/login',
    payload: {
      username: 'willin',
      password: 'PASSWORD'
    }
  });
  assert.equal(response.statusCode, 302);
});

test('POST /login 401', async () => {
  const response = await server.inject({
    method: 'POST',
    url: '/login',
    payload: {
      username: 'willin',
      password: 'Ww10842073305zZa28v3PO5Ok0L63IdA'
    }
  });
  assert.equal(response.statusCode, 401);
});

test('POST /login Invalid Params 403', async () => {
  const response = await server.inject({
    method: 'POST',
    url: '/login',
    payload: {
      username: 'willin'
    }
  });
  assert.equal(response.statusCode, 403);
});

test('GET /doc 200', async () => {
  const response = await server.inject({
    method: 'GET',
    url: location
  });
  assert.equal(response.statusCode, 200);
});

test('GET /doc 302', async () => {
  const response = await server.inject({
    method: 'GET',
    url: '/doc?'
  });
  assert.equal(response.statusCode, 302);
});

Benchmark

性能对比测试框架 Matcha: https://github.com/logicalparadox/matcha

使用场景

技术选型,如图形验证码,在 NPM 包选取使用canvas还是ccap时可以用。

或,一个问题,有多种解决方案,选择采用哪一种方案的时候。

注意: 所有需要做选择的场景,最好都先做一下对比。

结果报告示例

ATL (After v1.0.1)
  if > (true) .................................... 4,752,967 op/s
  if = (true) .................................... 4,653,896 op/s
  if < (false) ................................... 4,612,560 op/s

Left Shift (ATL v1.0.0)
  << > (true) .................................... 2,562,098 op/s
  << = (true) .................................... 2,473,787 op/s
  << < (false) ................................... 2,458,286 op/s

示例代码

suite('ATL', function () {
  bench('if > (true)', function () {
    atl('1.6.7', '1.4.4');
  });
  bench('if = (true)', function () {
    atl('1.4.4', '1.4.4');
  });
  bench('if < (false)', function () {
    atl('1.1.6', '1.4.4');
  });
});

suite('Left Shift', function () {
  bench('<< > (true)', function () {
    atls('1.6.7', '1.4.4');
  });
  bench('<< = (true)', function () {
    atls('1.4.4', '1.4.4');
  });
  bench('<< < (false)', function () {
    atls('1.1.6', '1.4.4');
  });
});

源码位于: https://github.com/WulianCC/node-atl/blob/master/benchmark/parse.js

你可能感兴趣的:(javascript,tdd,开发语言,ecmascript,前端,后端,学习方法)