React单元测试笔记
什么是单元测试
单元测试(unit testing),是指对软件中的最小可测试单元进行检查和验证。
React常用的单元测试工具
Jest+Enzyme
Jest使用
安装
用yarn安装jest:yarn add --dev jest
或者npm:
npm install --save-dev jest
使用Babel
通过yarn
安装依赖:
1 | yarn add --dev babel-jest @babel/core @babel/preset-env |
在 babel.config.js
文件里添加配置:
1 | // babel.config.js |
2 | module.exports = { |
3 | presets: [ |
4 | [ |
5 | '@babel/preset-env', |
6 | { |
7 | targets: { |
8 | node: 'current', |
9 | }, |
10 | }, |
11 | ], |
12 | ], |
13 | }; |
例子
首先创建一个 sum.js
文件:
1 | function sum(a, b) { |
2 | return a + b; |
3 | } |
4 | module.exports = sum; |
然后创建 sum.test.js
:
1 | const sum = require('./sum'); |
2 | |
3 | test('adds 1 + 2 to equal 3', () => { |
4 | expect(sum(1, 2)).toBe(3); |
5 | }); |
添加这部分代码到 package.json
:
1 | { |
2 | "scripts": { |
3 | "test": "jest" |
4 | } |
5 | } |
最后运行yarn test
或者 npm run test
,jest将会打印如下的输出:
1 | PASS ./sum.test.js |
2 | ✓ adds 1 + 2 to equal 3 (5ms) |
基本方法
分组(Test Group):
describe(name, fn)
describe
创建一个将几个相关测试组合在一起的块,这不是必须的,而且可以嵌套。1
const myBeverage = {
2
delicious: true,
3
sour: false,
4
};
5
6
describe('my beverage', () => {
7
test('is delicious', () => {
8
expect(myBeverage.delicious).toBeTruthy();
9
});
10
11
test('is not sour', () => {
12
expect(myBeverage.sour).toBeFalsy();
13
});
14
});
测试用例(Test Case):
test(name, fn, timeout)
test是jest.It的别名。
test用来编写测试方法。
1
test('did not rain', () => {
2
expect(inchesOfRain()).toBe(0);
3
});
断言(Assert):
expect(value).toBe(value)
对结果进行断言。
expect判定条件
toBe匹配器
not判定相反的结果
1
expect(2 + 2).toBe(4);
2
expect(2 + 2).not.toBe(5);
匹配器(Matchers)
普通匹配器
最简单的测试值的方法是看是否精确匹配。
1 | test('two plus two is four', () => { |
2 | expect(2 + 2).toBe(4); |
3 | }); |
Truthiness
在测试中,你有时需要区分 undefined
、 null
,和 false
,但有时你又不需要区分。 Jest 让你明确你想要什么。
toBeNull
只匹配null
toBeUndefined
只匹配undefined
toBeDefined
与toBeUndefined
相反toBeTruthy
匹配任何为真的if
语句toBeFalsy
匹配任何 为假的if
语句
1 | test('null', () => { |
2 | const n = null; |
3 | expect(n).toBeNull(); |
4 | expect(n).toBeDefined(); |
5 | expect(n).not.toBeUndefined(); |
6 | expect(n).not.toBeTruthy(); |
7 | expect(n).toBeFalsy(); |
8 | }); |
9 | |
10 | test('zero', () => { |
11 | const z = 0; |
12 | expect(z).not.toBeNull(); |
13 | expect(z).toBeDefined(); |
14 | expect(z).not.toBeUndefined(); |
15 | expect(z).not.toBeTruthy(); |
16 | expect(z).toBeFalsy(); |
17 | }); |
数字
多种比较数值的匹配器。
1 | test('two plus two', () => { |
2 | const value = 2 + 2; |
3 | expect(value).toBeGreaterThan(3); |
4 | expect(value).toBeGreaterThanOrEqual(3.5); |
5 | expect(value).toBeLessThan(5); |
6 | expect(value).toBeLessThanOrEqual(4.5); |
7 | |
8 | // toBe and toEqual are equivalent for numbers |
9 | expect(value).toBe(4); |
10 | expect(value).toEqual(4); |
11 | }); |
比较浮点数相等时,使用toBeCloseTo
而不是toEqual
,可以避免舍入误差导致的测试错误。
1 | test('两个浮点数字相加', () => { |
2 | const value = 0.1 + 0.2; |
3 | //expect(value).toBe(0.3); 这句会报错,因为浮点数有舍入误差 |
4 | expect(value).toBeCloseTo(0.3); // 这句可以运行 |
5 | }); |
字符串
可以用 toMatch
通过正则表达式检查字符串︰
1 | test('there is no I in team', () => { |
2 | expect('team').not.toMatch(/I/); |
3 | }); |
4 | |
5 | test('but there is a "stop" in Christoph', () => { |
6 | expect('Christoph').toMatch(/stop/); |
7 | }); |
数组和迭代器
可以用toContain
匹配是否包含此元素。
1 | const shoppingList = [ |
2 | 'diapers', |
3 | 'kleenex', |
4 | 'trash bags', |
5 | 'paper towels', |
6 | 'beer', |
7 | ]; |
8 | |
9 | test('the shopping list has beer on it', () => { |
10 | expect(shoppingList).toContain('beer'); |
11 | expect(new Set(shoppingList)).toContain('beer'); |
12 | }); |
例外
如果你想要测试的特定函数抛出一个错误,在它调用时,使用 toThrow
。
1 | function compileAndroidCode() { |
2 | throw new ConfigError('you are using the wrong JDK'); |
3 | } |
4 | |
5 | test('compiling android goes as expected', () => { |
6 | expect(compileAndroidCode).toThrow(); |
7 | expect(compileAndroidCode).toThrow(ConfigError); |
8 | |
9 | // You can also use the exact error message or a regexp |
10 | expect(compileAndroidCode).toThrow('you are using the wrong JDK'); |
11 | expect(compileAndroidCode).toThrow(/JDK/); |
12 | }); |
更多
测试 React Apps
使用Create React App安装
Create React App 初始化的项目预置了Jest,只需要添加react-test-renderer`来渲染快照.
不使用Create React App安装
如果现有项目不是通过Creact React App创建,则需要添加一些依赖来搭配使用
1 | yarn add --dev jest babel-jest @babel/preset-env @babel/preset-react react-test-renderer |
添加这些配置到相应的文件,
current-version
为当前依赖的最新版本号
1 | // package.json |
2 | "dependencies": { |
3 | "react": "<current-version>", |
4 | "react-dom": "<current-version>" |
5 | }, |
6 | "devDependencies": { |
7 | "@babel/preset-env": "<current-version>", |
8 | "@babel/preset-react": "<current-version>", |
9 | "babel-jest": "<current-version>", |
10 | "jest": "<current-version>", |
11 | "react-test-renderer": "<current-version>" |
12 | }, |
13 | "scripts": { |
14 | "test": "jest" |
15 | } |
16 | // babel.config.js |
17 | module.exports = { |
18 | presets: ['@babel/preset-env', '@babel/preset-react'], |
19 | }; |
搭配Enzyme使用
运行yarn add --dev enzyme
添加Enzyme。如果您使用的是低于15.5.0的React版本,则还需要安装react-addons-test-utils
。
例子:
1 | import React from 'react'; |
2 | import {shallow} from 'enzyme'; |
3 | import CheckboxWithLabel from '../CheckboxWithLabel'; |
4 | |
5 | test('CheckboxWithLabel changes the text after click', () => { |
6 | // Render a checkbox with label in the document |
7 | const checkbox = shallow(<CheckboxWithLabel labelOn="On" labelOff="Off" />); |
8 | expect(checkbox.text()).toEqual('Off'); |
9 | checkbox.find('input').simulate('change'); |
10 | expect(checkbox.text()).toEqual('On'); |
11 | }); |