单元测试
单元测试
什么是单元测试
单元测试(英语:Unit Testing)又称为模块测试,是针对程序模块(软件设计的最小单位)来进行正确性检验的测试工作。程序单元是应用的最小可测试部件。在过程化编程中,一个单元就是单个程序、函数、过程等;对于面向对象编程,最小单元就是方法,包括基类(超类)、抽象类、或者派生类(子类)中的方法。 ——维基百科
单元测试就是开发过程中模块、功能、函数等最小单位的测试。
单元测试在 CI/CD 中的作用?
CI/CD通常指的是持续集成和持续交付或持续部署的组合实践。
CI 持续集成(Continuous Integration)
成功的 CI 意味着应用代码的新更改会定期构建、测试并合并到共享存储库中。该解决方案可以解决在一次开发中有太多应用分支,从而导致相互冲突的问题。
CD 持续交付和/或持续部署(Continuous Delivery)/(Continuous Deployment)
持续交付
完成 CI 中构建及单元测试和集成测试的自动化流程后,持续交付可自动将已验证的代码发布到存储库。
持续部署
作为持续交付——自动将生产就绪型构建版本发布到代码存储库——的延伸,持续部署可以自动将应用发布到生产环境。
一般情况下,在进行代码的持续集成时,一旦开发人员对应用所做的更改被合并,系统就会通过自动构建应用并运行不同级别的自动化测试(通常是单元测试和集成测试)来验证这些更改,确保这些更改没有对应用造成破坏。
为什么需要单元测试
- 必要性:JavaScript 缺少类型检查,编译期间无法定位到错误,单元测试可以帮助你测试多种异常情况。
- 正确性:测试可以验证代码的正确性,在上线前做到心里有底。
- 自动化:通过编写测试用例,可以做到一次编写,多次运行。
- 保证重构:保证代码重构的安全性,在重构代码之后,测试用例能保证重构后的代码功能正常。
- 测试驱动开发,指导设计:代码被测试的前提是代码本身的可测试性,那么要保证代码的可测试性,就需要在开发中注意 API 的设计,TDD 将测试前移就是起到这么一个作用,同时测试用例也相当于一个开发文档。
测试框架
框架 | 断言 | 异步 | 代码覆盖率 |
---|---|---|---|
Mocha | 不支持(需要其他库支持)chai | 友好 | 不支持(需要其他库支持) |
Jest | 默认支持 | 友好 | 支持 |
- Jest 开箱即用。
- Mocha 生态较好,但是需要配合其他库一起使用。
什么是断言?
”断言“,个人理解即为”用彼代码断定测试此代码的正确性,检验并暴露此代码的错误。就是判断源码的实际执行结果与预期结果是否一致,如果不一致就抛出一个错误。
怎么做单元测试
安装依赖
npm i jest @types/jest babel-jest @babel/core @babel/preset-env -D
babel.config.js
module.exports = { presets: [["@babel/preset-env", { targets: { node: "current" } }]] };
一个简单的例子尝试
./sum.js
function sum(a, b) { return a + b; } module.exports = sum;
创建一个 math.test.js 文件
const sum = require('../sum'); test('adds 1 + 2 to equal 3', () => { expect(sum(1, 2)).toBe(3); });
在 package.json 文件里面加上测试命令
{ "scripts": { "test": "jest" } }
进行测试并统计覆盖率命令
覆盖率统计项
从覆盖率的图片可以看到一共有 4 个统计项:
- Stmts(statements):语句覆盖率,程序中的每个语句是否都已执行。
- Branch:分支覆盖率,是否执行了每个分支。
- Funcs:函数覆盖率,是否执行了每个函数。
- Lines:行覆盖率,是否执行了每一行代码。
前端自动化测试
TDD (Test-driven development)
TDD—测试驱动开发,侧重点偏向开发,通过测试用例来规范约束开发者编写出质量更高、bug 更少的代码。先写测试用例,再写功能模块。
测试驱动开发(英语:Test-driven development,缩写为 TDD)是一种软件开发过程中的应用方法,由极限编程中倡导,以其倡导先写测试程序,然后编码实现其功能得名。测试驱动开发始于 20 世纪 90 年代。测试驱动开发的目的是取得快速反馈并使用“illustrate the main line”方法来构建程序。 ——维基百科
TDD 基本流程
TDD 的优点
- 保证代码质量
- 测试覆盖率高,因为后编写代码,因此测试用例基本都能照顾到;
TDD 的缺点
- 代码量增多,大多数情况下测试代码是功能代码的两倍甚至更多;
- 业务耦合度高,测试用例中使用了业务中一些模拟的数据,当业务代码变更的时候,要去重新组织测试用例;
BDD (Behavior-driven development)
BDD — 行为驱动开发,由外到内的开发方式,从外部定义业务成果,再深入到能实现这些成果,每个成果会转化成为相应的包含验收标准。先写主功能模块,再写测试用例。
行为驱动开发(英语:Behavior-driven development,缩写BDD)是一种敏捷软件开发的技术,它鼓励软件项目中的开发者、QA和非技术人员或商业参与者之间的协作。BDD 最初是由 Dan North 在 2003 年命名[1],它包括验收测试和客户测试驱动等的极限编程的实践,作为对测试驱动开发的回应。 ——维基百科
BDD 的开发流程
1、开发人员和非开发人员一起讨论确认需求
2、以一种自动化的方式将需求建立起来,并确认是否一致
3、最后,实现每个文档示例描述的行为,并从自动化测试开始以指导代码的开发
BDD 的优点:
- 由于仅关注功能,不关注实现细节,有利于测试代码和实际代码解耦
- 由于大多数为编写集成测试,相比 TDD 有更好的开发效率
BDD 的缺点:
- 因为以功能性的集成测试为主,因此不是那么关注每个函数功能,测试覆盖率比较低
- 没有 TDD 那么严格的保证代码质量
TDD VS BDD
功能 | TDD(Test-driven development) | BDD(Behavior-driven development) |
---|---|---|
定义 | 测试驱动开发 | 行为驱动开发 |
思想 | 白盒测试,从代码角度出发,完成高质量代码为目的。 | 黑盒测试,从用户角度出发,完成需求为目的。 |
开发流程 | 编写单元测试 编写代码 通过测试 代码重构 重复步骤 |
编写代码 编写测试用例 通过测试 代码重构 重复步骤 |
代码覆盖率 | 高 | 低 |
测试类型 | 单元测试 | 集成测试 |
代码质量 | 高 | 一般 |
测试代码量 | 高 | 低 |
因此个人建议:
- 在开发组价库,工具函数库时使用 TDD
- 在开发业务系统时使用 BDD
问题与反思
- 单元测试具有学习成本,在哪些地方适合编写单元测试?
- 单元测试是否可以实现不同浏览器下的差异性测试?
- 在公司项目中进行测试代码的编写可行性有多大?