认识单元测试
在 web 前端领域,单元测试通常包括:对某个 JS 的方法进行测试,对某个组件进行测试。除了单元测试,前端经常会有端到端测试。相对于端到端测试来说,单元测试编写更复杂。但是完整的单元测试的样例能够覆盖更多端到端测试覆盖不到的点,对于前端代码通常比较关键的模块可以通过添加单元测试来规避后续修改或者重构带来的风险。单元测试样例的编写过程也有助于进一步审视模块的功能。
单元测试适用于功能不会经常改动的工具方法模块和一些基础的公共组件,对于会经常在快速迭代中更新的业务组件和功能模块端到端的测试会更适合,但这并不是说不需要写单元测试。这其实是一个投入和产出比的一个权衡,编写单元测试可能会需要频繁的更新测试样例,对于部分业务尤其是中后台的应用来说成本是偏高的。
前端怎么做测试
在 React 诞生之前,前端的单元测试往往只能针对于一些纯粹的 JS 模块。由于对浏览器环境的依赖,很难去做涉及到 dom 操作的模块的单元测试。但是对于前端来说,大部分代码其实都是 UI 组件,这就导致长期以来前端的代码甚至一些开源的被应用得很广泛的 UI 组件库都缺乏完整的单元测试。
但是 React 的诞生伴随着虚拟 dom 被发明,这使得前端组件的测试变得更方便了。虚拟 dom 使得一个组件可以脱离真实的浏览器环境模拟 dom 的相关操作。我们可以通过测试虚拟 dom 的表现是否正常来测试组件的逻辑,让编写组件的测试能够脱离对浏览器 dom 环境的依赖。
在 umi 中,内置了 jest 作为单元测试的库,接下来我们会介绍如何使用 jest 对 JS 方法或者组件进行测试。
使用Jest
umi内置了jest测试。执行umi test 会匹配所有 .test.js 结尾的文件运行。通常我们约定把测试的代码统一放到test文件夹下,当然你也可以按照你的习惯组织,比如可以和测试对应的模块放到一起。
非umi环境下安装参考上次分享的内容,内容在我的博客中:
http://xuxiao.wang/detail/单元测试-Jest入门1
匹配器-普通匹配
- 最简单的测试值的方法是看是否精确匹配。
test('测试值', () => {
expect(2 + 2).toBe(4);
});
测试一个对象的值是否相等
test('测试对象', () => {
const data = {one: 1};
data['two'] = 2;
expect(data).toEqual({one: 1, two: 2});
});
匹配器-真值匹配
- toBeNull 只匹配 null
- toBeUndefined 只匹配 undefined
- toBeDefined 与 toBeUndefined 相反
- toBeTruthy 匹配任何 if 语句为真
- toBeFalsy 匹配任何 if 语句为假
匹配器-数字匹配
- toBeGreaterThan 匹配大于
- toBeGreaterThanOrEqual 匹配大于等于
- toBeLessThan 匹配小于
- toBeLessThanOrEqual 匹配小于等于
- toBe 匹配等于
- toEqual 匹配等于,等价于 toBe
- toBeCloseTo 匹配浮点数相等,不会因为误差导致不匹配
匹配器-字符串匹配
- toMatch 匹配字符串
- 使用正则匹配一个字符串。测试用例匹配不包含字母I
test(‘匹配字符串', () => {
expect('team').not.toMatch(/I/);
});
匹配器-数组或其他可迭代对象
- toContain检查一个数组或可迭代对象是否包含某个特定项
使用正则匹配一个字符串。测试用例匹配不包含字母I
const shoppingList = [ 'diapers', 'kleenex', 'trash bags', 'paper towels', 'beer', ];
test('匹配数组中是否包含某个元素', () => {
expect(shoppingList).toContain('beer’);
expect(new Set(shoppingList)).toContain('beer’);
});
匹配器-异常
- toThrow 匹配异常
使用正则匹配一个字符串。测试用例匹配不包含字母I
expect(compileAndroidCode).toThrow();
compileAndroidCode 是一段可能会抛出异常的方法,如果抛出异常则匹配