前言:这篇笔记适合关于单元测试的知识点扫盲。
测试包含单元测试、性能测试、安全测试和功能测试等几个方面。
单元测试主要用于检测代码的行为是否符合预期。
单元测试的意义在于每个测试用例的覆盖都是一种可能的承诺。如果API升级时,测试用例可以很好地检查是否向下兼容。
编写可测试代码有以下几个原则可以遵循:
- 单一职责。将复杂的功能解耦分离。
- 接口抽象
- 层次分离
单元测试主要包含断言、测试框架、测试用例、测试覆盖率、mock、持续集成等几个方面。
质量没有保证的代码,主要源于以下两点:
- 没有对输出结果进行任何检测
- 输入条件覆盖率并不完备
如何对输出结果进行检测,以确认方法调用是正常的,是最基本的测试点。
1、断言
断言是用于检查程序在运行时是否满足期望。在断言规范中,我们定义了以下几种检测方法:
ok() 判断结果是否为真
equal() 判断实际值与期望值是否相等
notEqual() 判断实际值与期望值是否不相等
deepEqual() 判断实际值与期望值是否深度相等(对象或数组的元素是否相等)
notDeepEqual() 判断实际值与期望值是否深度不相等
strictEqual() 判断实际与期望值是否严格相等(相当于===)
notStrictEqual() 判断实际值与期望值是否严格不相等(!==)
throws() 判断代码块是否抛出异常
2、测试框架
记录下抛出的异常并继续执行,最后生成测试报告 。这些任务的承担者就是测试框架。测试框架用于为测试服务,它本身并不参与测试,主要用于管理测试用例和生成测试报告,提升测试用例的开发速度,提高测试用例的可维护性和可读性,以及一些周边性的工作。
测试风格
我们将测试用例的不同组织方式称为测试风格,流行的单元测试风格主要有TDD(测试驱动开发)和BDD(行为驱动开发)两种,它们的差别如下所示:
- 关注点不同。TDD关注所有功能是否被正确实现,每一个功能都具备对应的测试用例;BDD关注整体行为是否符合预期,适合自顶向下的设计方式。
- 表达方式不同。TDD的表达方式偏向于功能说明书的风格;BDD的表述方式更接近于自然语言的习惯。
BDD风格的示例:
describe('Array', function() {
before(function() {});
describe('#indexOf()', function() {
it('should return -1 when not present', function() {
[1, 2, 3].indexOf(4).should.equal(-1);
})
})
})
BDD对测试用例的组织采用describe和it进行组织。describe可以描述多层级的结构,具体到测试用例时,用it。
提供before, after, beforEach, afterEach, 这4钩子方法,用于协助describe中测试用例的准备、安装、卸载和回收等工作。
before和after分别在进入和退出describe时触发执行,beforeEach和afterEach则分别在describe中每一个测试用例执行前和执行后触发执行。
TDD风格示例略
3、测试代码的文件组织
包规范中定义了测试代码存在于test目录中.
4、测试用例
一个行为或者功能需要有完善的、多方面的测试用例,一个测试用例中包含至少一个断言。
测试用例最少需要通过正向测试和反向测试来保证测试对功能的覆盖,这是最基本的测试用例。
5、测试覆盖率
测试覆盖率是单元测试中的一个重要指标,它能够概括性地给出整体的覆盖度,也能明确地给出统计到行的覆盖情况。单元测试的覆盖率方便我们定位没有测试到的代码行。
6、mock
开发者遗漏的一些异常案例,其中相当大一部分原因在于异常情况比较难实现。在测试领域里,模拟异常其实是一个不小的科目,它有着一个特殊的名词Mock。通过伪造调用方法来测试上层代码的健壮性等。