首先,按照入门指南中的文档,在 Jest 中启用 Babel 支持。
让我们实现一个简单的模块,它从 API 获取用户数据并返回用户名。
// user.js
import request from './request';
export function getUserName(userID) {
return request('/users/' + userID).then(user => user.name);
}
在上面的实现中,我们期望 request.js
模块返回一个 promise。我们链式一个调用到 then 来接收用户名。
现在设想一个 request.js
的实现,它进入网络并获取一些用户数据:
// request.js
const http = require('http');
export default function request(url) {
return new Promise(resolve => {
// This is an example of an http request, for example to fetch
// user data from an API.
// This module is being mocked in __mocks__/request.js
http.get({path: url}, response => {
let data = '';
response.on('data', _data => (data += _data));
response.on('end', () => resolve(data));
});
});
}
因为我们不想在测试中进入网络,所以我们将在_mocks__
文件夹中为request.js
模块创建一个手动模拟(该文件夹区分大小写,所以不能使用_mocks__
)。它可以是这样的:
// __mocks__/request.js
const users = {
4: {name: 'Mark'},
5: {name: 'Paul'},
};
export default function request(url) {
return new Promise((resolve, reject) => {
const userID = parseInt(url.substr('/users/'.length), 10);
process.nextTick(() =>
users[userID]
? resolve(users[userID])
: reject({
error: 'User with ' + userID + ' not found.',
}),
);
});
}
现在让我们为异步功能编写一个测试。
// __tests__/user-test.js
jest.mock('../request');
import * as user from '../user';
// The assertion for a promise must be returned.
it('works with promises', () => {
expect.assertions(1);
return user.getUserName(4).then(data => expect(data).toEqual('Mark'));
我们调用 jest.mock('../request')
来告诉 Jest 使用我们手动的 mock。它期望返回值是一个将被 resolved 的 Promise。你可以链接任意多的 Promise,并随时调用 expect,只要最后返回一个 Promise。
.resolves
这儿有一种更简洁的方式,使用 resolves
可以获取到一个未包装的 fulfilled promise 的值。如果这个 promise 被 rejected,这个断言将会失败。
it('works with resolves', () => {
expect.assertions(1);
return expect(user.getUserName(5)).resolves.toEqual('Paul');
});
async / await
使用 async / await
语法编写测试更加简单。下面是相同的例子此方法的写法:
// async/await can be used.
it('works with async/await', async () => {
expect.assertions(1);
const data = await user.getUserName(4);
expect(data).toEqual('Mark');
});
// async/await can also be used with `.resolves`.
it('works with async/await and resolves', async () => {
expect.assertions(1);
await expect(user.getUserName(5)).resolves.toEqual('Paul');
});
要在项目中启动 async/await,安装 @babel/preset-env
并在 babel.config.js
文件中启用该特性。
错误处理
错误可以使用 .catch
方法处理。确保添加了 expect.assertions
确保确定次数的断言调用。不然,一个 fulfilled promise 将不会导致测试失败:
// Testing for async errors using Promise.catch.
test('tests error with promises', () => {
expect.assertions(1);
return user.getUserName(2).catch(e =>
expect(e).toEqual({
error: 'User with 2 not found.',
}),
);
});
// Or using async/await.
it('tests error with async/await', async () => {
expect.assertions(1);
try {
await user.getUserName(1);
} catch (e) {
expect(e).toEqual({
error: 'User with 1 not found.',
});
}
});
.rejects
这个 .rejects
工作原理类似 .resolves
。如果这个 promise 是 fulfilled,这个测试将自动失败。
// Testing for async errors using `.rejects`.
it('tests error with rejects', () => {
expect.assertions(1);
return expect(user.getUserName(3)).rejects.toEqual({
error: 'User with 3 not found.',
});
});
// Or using async/await with `.rejects`.
it('tests error with async/await and rejects', async () => {
expect.assertions(1);
await expect(user.getUserName(3)).rejects.toEqual({
error: 'User with 3 not found.',
});
});
参考:
expect.assertions(number) 期待断言的次数
expect.assertions(number)
验证在测试期间调用一定数量的断言。这在测试异步代码时非常有用,以确保回调中的断言确实被调用了。
例如,我们有一个函数 doAsync
接收两个回调 callback1
和 callback2
,它们将以未知的顺序异步调用它们。我们可以这样测试:
test('doAsync calls both callbacks', () => {
expect.assertions(2); // 期待发生两次断言
function callback1(data) {
expect(data).toBeTruthy();
}
function callback2(data) {
expect(data).toBeTruthy();
}
doAsync(callback1, callback2);
});
expect.assertions(2)
确保实际调用了两个回调。
网友评论