TDD单元测试

TDD(Test Driven Development)

TDD就是先写测试, 后写程序

不是每个人都想写测试的, 很大原因是懒

:confused:我就是开发的, 跑一下看看就知道对不对, 要什么测试, 而且测试就是我写的, 没啥用啊

测试的意义

  • 有说服力: 如果测试说测出bug了, 至少我能告诉他, 在这个case下程序是正确的
  • 容易接手: 同事要辞职, 我却不能肯定他的代码对不对, 如果有测试就没这么多忧虑了
  • 卖相好: 自己写一个项目, 写的明明比别人好, api比人家简洁, 但为啥大家不选我的项目呢. 这时候就要去看看是不是自己的测试用例不如别人长

TDD和Unit Test的关系

什么是Unit Test?

  • Unit表示最小的测试单位, 不可再分, 因此Unit Test绝不包含逻辑

  • 两个Unit Test Case之间没有依赖, 没有联系

  • 可重复测试

TDD说的是什么时候测试, Unit Test说的是测试的是什么, 他们毫无关联


TDD和BDD

BDD是TDD的扩展, 本质是相同的, 但是API不同, 不过光是should.equal, 就让人感觉有点蛋疼. 更别说还有to, be, been, is, that...这一堆东西了

TDD一般用assert, 而nodejs自带了这个lib, 因此我毅然选择先入门TDD(喂我怎么又暴露自己不懂测试啊:scream:)

TDD是让测试来驱动开发, 因此我们很容易归纳出适用TDD的场景

  1. api明确
  2. 员工不靠谱, 需要约束

TDD的主要API(mocha给的, tdd本身只是说测试早于开发)

  • suite
  • test
  • ok或者assert

:question:为什么光有assert还不行?

assert的功能简洁明了, 甚至是koa也直接用assert不用复杂的tdd测试框架

但大型项目中还是用测试框架为好, 因为assert是直接throw Error的,也就是只要出错即中断, 试想一下, 如果是10个人同时在搞这个项目, 测试用例跑不通, 但只看到一个错误, 那该有多蛋疼啊, 看不到错误的9个人只能干等着, 不知道后面还有没有错误


mocha学习

test

test用法很简单

test('api-1', function() {
  ok(false, 'should true')
})

聪明的你一定想到了, test就俩作用, 一个是告诉框架这测试的是啥东西, 另一个就是第二个参数必然是由try catch包裹起来的, 这样我们可以完整的跑完所有test

test('api-1', function() {
  ok(false, 'should true')
  doSomethingElse() // 显然, 如果上面出错了, 这里是执行不到的
  ok(true, 'should ok') // 除非是故意要全部正确, 不然连续写ok或者assert是没有意义的
})

但有一个例外, 即便错了还能执行下去, 这就是mocha中处理async(异步)的函数done

首先我们要知道这样写程序会出错, 因为setTimeout中的函数是没有上下文的, 不属于test里, 因此错误不会被catch

test('api-2', function() {
  setTimeout(function() {
    ok(false)
  })
})

但我们用上done就不同了

test('api-2', function(done) {
  setTimeout(function() {
    ok(false)
    done()
  }, 1000)
})

这样连异步的错误都捕获了:smile:, 当然这也归功于nodejs中的uncaughtException, 可以用process.on进行捕获

suite

suite 这个函数就简单了, 意如其名, 一套, 用来将test归类, 相当于是一个namespace

mocha中用suite的ui(接口)有TDD和QUnit两种

TDD是这样的, 优点是可以嵌套

suite('Array', function(){
  setup(function(){
    // ...
  });

  suite('#indexOf()', function(){
    test('should return -1 when not present', function(){
      assert.equal(-1, [1,2,3].indexOf(4));
    });
  });
});

QUnit的优点是少了嵌套, 适用于api层级很平的项目, 不像TDD那样可以嵌套

suite('Array');

test('#length', function(){
  var arr = [1,2,3];
  ok(arr.length == 3);
});

test('#indexOf()', function(){
  var arr = [1,2,3];
  ok(arr.indexOf(1) == 0);
  ok(arr.indexOf(2) == 1);
  ok(arr.indexOf(3) == 2);
});

suite('String');

test('#length', function(){
  ok('foo'.length == 3);
});

我个人很喜欢QUnit, 写了还能前后端一起用