Jest
使用 Jest 测试框架
软件测试向相关开发者提供有关被测产品与服务的质量信息。在软件测试时常涉及手动或自动(半自动)检查的过程,以确保代码的按需运行与健壮性。市面上主流的前端测试框架有 Jasmine、MOCHA、Jest。
进行自动化测试与回归测试(回归测试是指修改了旧代码后,重新进行测试并确认修改后没有引入新的错误或导致其他代码产生异常)后发现 Jest 在 IDE拓展性、测试文件隔离性、并行测试以及测试覆盖率等几个方面具有优势。
测试类型:
- 单元测试——独立检查代码的各个单元组件,确保代码的每个单元组件都按需求运行。
- 集成测试——将单元组件组合并测试协同工作,暴露各个单元在进行交互中可能存在的错误。
- End-to-End 测试——从头到尾的检查应用程序的系统流程以及行为预期,识别系统错误和选择优化方向,确保系统的安全级别。
快速上手
- 安装 Jest
# 使用 yarn 安装 Jest
yarn add --dev jest
# 使用 npm 安装 Jest
npm install --save-dev jest
- 使用匹配器
// testjsfile.js
function testjsfile(a, b) {
return 'zsxzy';
}
module.exports = testjsfile;
// nameWriteCasually.test.js
const testjsfile = require('./testjsfile');
test('theMatchersNameWriteCasually', () => {
const expectedValue = testjsfile();
const actualValue = 'zsxzy';
// toBe => Object.is(value1, value2);仅比较值则使用toEqual
expect(expectedValue).toBe(actualValue);
});
- 修改 package.json 配置内容
{
"scripts": {
"test": "jest"
}
}
npm test nameWriteCasually.test.js
输出 Jest 结果如下。
这里需要注意的是 Jest 使用 CommonJS 标准,如果未安装 Babel 转换器就使用 ES6 Modules 语法 (export\import) ,则会出现错误。
// testjsfile.js
export default function testjsfile() {
return 'zsxzy';
}
// nameWriteCasually.test.js
import testjsfile from './testjsfile'
test('theMatchersNameWriteCasually', () => {
const expectedValue = testjsfile();
const actualValue = 'zsxzy';
expect(expectedValue).toBe(actualValue);
});
Jest encountered an unexpected token
Jest failed to parse a file. This happens e.g. when your code or its dependencies use non-standard JavaScript syntax, or when Jest is not configured to support such syntax.
Out of the box Jest supports Babel, which will be used to transform your files into valid JS based on your Babel configuration.
By default "node_modules" folder is ignored by transformers.
Jest 中存在 babel-jest 组件,使用 yarn test
或者 npm run test
命令时,会先检测根目录开发环境是否安装 babel 核心包以及 .babelrc
存在与否,若存在则会转换后再进行测试。
# 安装 babel
yarn add @babel/core@7.4.5 @babel/preset-env@7.4.5 --dev
npm install @babel/core@7.4.5 @babel/preset-env@7.4.5 -D
// 检查开发环境依赖
"devDependencies": {
"@babel/core": "^7.4.5",
"@babel/preset-env": "^7.4.5",
"jest": "^27.0.6"
}
// 配置 .babelrc 规则
{
"presets": [
[
"@babel/preset-env",{
"targets":{
"node": "current"
}
}
]
]
}
常用匹配器
在上面的代码中,expect () 返回了一个"预期"的对象。通常不会对这些期望对象调用过多的匹配器。.toBe() 是匹配器。当 Jest 运行时,它会跟踪所有失败的匹配器,以便打印出错误消息。
.toBe() 是使用 Object.is 来进行精准匹配的测试。如果想要检查对象的值,则使用 .toEqual() 递归检查对象或数组的每个字段。需要相反匹配则在匹配器前加上 .not。
test('对象赋值', () => {
const useToEqual = {name: 'zs'};
useToEqual['age'] = 23;
expect(useToEqual).toEqual({name: 'zs', age: 23});
});
test('adding positive numbers is not zero', () => {
for (let a = 1; a < 3; a++) {
for (let b = 1; b < 3; b++) {
expect(a + b).not.toBe(0);
}
}
});
PASS ./useToEqual.test.js
✓ 对象赋值 (2 ms)
✓ adding positive numbers is not zero (1 ms)
代码中的 undefined, null, and false 有不同含义,用真值判断则可以在测试时不加区分。Jest提供 helpers 使用。
- toBeNull 只匹配 null
- toBeUndefined 只匹配 undefined
- toBeDefined 与 toBeUndefined 相反
- toBeTruthy 匹配任何 if 语句为真
- toBeFalsy 匹配任何 if 语句为假
test('null', () => {
const n = null;
expect(n).toBeNull(); // toBeNull 只匹配 null
expect(n).toBeDefined();
expect(n).not.toBeUndefined(); // null !== Undefined
expect(n).not.toBeTruthy(); // null 非真
expect(n).toBeFalsy();
});
test('zero', () => {
const z = 0;
expect(z).toBeDefined();
expect(z).not.toBeUndefined();
expect(z).not.toBeTruthy(); // 0 非真
expect(z).toBeFalsy(); // 0 假值
});
Jest 中比较数字等价的匹配器:
- toBeGreaterThan 大于
- toBeGreaterThanOrEqual 大于等于
- toBeLessThan 小于
- toBeLessThanOrEqual 小于等于
- toBe 精确比较
- toEqual 递归检查对象或数组的每个字段
- toBeCloseTo 舍去误差比较浮点数相等
test('calc', () => {
const value = 2 + 2;
expect(value).toBeGreaterThan(3);
expect(value).toBeGreaterThanOrEqual(3.5);
expect(value).toBeGreaterThanOrEqual(4);
expect(value).toBeLessThan(5);
expect(value).toBeLessThanOrEqual(4.5);
// toBe and toEqual are equivalent for numbers
expect(value).toBe(4);
expect(value).toEqual(4);
});
test('两个浮点数字相加', () => {
const value = 0.1 + 0.2;
// expect(value).toBe(0.3); 因为浮点数有舍入误差报错
expect(value).toBeCloseTo(0.3); // 这句可以运行
});
Jest 使用 toMatch 正则表达式检查字符串。
test('stringMatch', () => {
expect('zairesinatra').not.toMatch(/x/i);
});
test('matchWord', () => {
expect('zsxzy').toMatch(/zsxzy/);
});
Jest 使用 toContain 检查数组及可迭代对象是否包含某个特定项。
const zsdev = [
'Java',
'Javascript',
'C++'
];
test('zsdev has it?', () => {
expect(zsdev).toContain('Java');
expect(new Set(zsdev)).toContain('Javascript');
});
Jest 在测试函数调用时可以使用 toThrow 抛出错误。
function compileCode() {
throw new Error('err');
}
test('throw Error', () => {
// 函数需要在 expect 的包装函数中调用,否则 toThrow 断言总是会失败
expect(() => compileCode()).toThrow(); // 验证成功抛出错误
expect(() => compileCode()).toThrow(Error); // 验证成功抛出错误
expect(() => compileCode()).toThrow('you get the wrong message'); // 错误显示
expect(() => compileCode()).toThrow(/err/);
});
异步代码测试
当有以异步方式运行的代码时,Jest 需要知道当前它测试的代码是否已完成,然后就可以转移到另一个测试。Jest有若干方法处理这种情况。
- callback回调
默认情况下,一旦到达运行上下文底部 Jest 测试立即结束。这样意味着这个测试将不能按预期工作。异步代码还在队列时,同步代码就执行到 fetchData,此时 Jest 测试就在调用回调函数前结束。
// 错误示范
test('error example', () => {
function callback(data) {
expect(data).toBe('errorExample');
}
setTimeout(callback,0); // 不传参就直接结束了——出现问题
});
使用单个参数调用 done,而不是将测试放在一个空参数的函数。Jest 会等参数回调函数执行结束后,结束测试。
test('solve callback', done => {
function callback(data) {
try {
expect(data).toBe('zsdev');
done();
} catch (error) {
done(error);
}
}
setTimeout(callback('zsdev'),0);
});
- Promise测试
Jest 会等待测试返回一个 Promise 成功与否进行测试异步代码。
test('the data is zsdev', () => {
return fetchData().then(data => {
expect(data).toBe('zsdev');
});
});
结束
本博客所有文章除特别声明外,均采用 CC BY-SA 4.0 协议,转载请注明出处!