阅读(988) (0)

Jest 异步示例

2021-08-10 17:19:37 更新

首先, 像Jest 从安装开始里面所说的那样, 启用babel的支持

让我们实现一个从 API 获取用户数据并返回用户名的模块。

  1. // user.js
  2. import request from './request';
  3. export function getUserName(userID) {
  4. return request('/users/' + userID).then(user => user.name);
  5. }

在上面的实现中,我们期望​request.js​模块返回一个 promise。我们链接一个调用来​then​接收用户名。

现在想象一个​request.js​进入网络并获取一些用户数据的实现:

  1. // request.js
  2. const http = require('http');
  3. export default function request(url) {
  4. return new Promise(resolve => {
  5. // 这是一个HTTP请求的例子, 用来从API获取用户信息
  6. // This module is being mocked in __mocks__/request.js
  7. http.get({path: url}, response => {
  8. let data = '';
  9. response.on('data', _data => (data += _data));
  10. response.on('end', () => resolve(data));
  11. });
  12. });
  13. }

因为我们在测试中不想去网络,所以我们将​request.js​在​__mocks__​文件夹中为我们的模块创建一个手动模拟(文件夹区分大小写,​__MOCKS__​将不起作用)。就像是这样:

  1. // __mocks__/request.js
  2. const users = {
  3. 4: {name: 'Mark'},
  4. 5: {name: 'Paul'},
  5. };
  6. export default function request(url) {
  7. return new Promise((resolve, reject) => {
  8. const userID = parseInt(url.substr('/users/'.length), 10);
  9. process.nextTick(() =>
  10. users[userID]
  11. ? resolve(users[userID])
  12. : reject({
  13. error: 'User with ' + userID + ' not found.',
  14. }),
  15. );
  16. });
  17. }

现在我们就来编写我们的异步函数的测试

  1. // __tests__/user-test.js
  2. jest.mock('../request');
  3. import * as user from '../user';
  4. //断言必须返回一个primose
  5. it('works with promises', () => {
  6. expect.assertions(1);
  7. return user.getUserName(4).then(data => expect(data).toEqual('Mark'));
  8. });

我们调用 ​jest.mock('../request ')​ 告诉jest 使用我们手动的创建的模拟数据。 ​it ​断言的是将会返回一个Promise对象,你可以在任何时候给​expect​打电话,只要你在最后回复一个承诺。

.resolves

有一种不那么冗长的方法​resolves​用于将已履行的 Promise 的值与任何其他匹配器一起解包。如果 Promise 被拒绝,则断言将失败。

  1. it('works with resolves', () => {
  2. expect.assertions(1);
  3. return expect(user.getUserName(5)).resolves.toEqual('Paul');
  4. });

async/await

也可以使用​async​/​await​语法编写测试。以下是如何编写与之前相同的示例:

  1. // 使用async/await
  2. it('works with async/await', async () => {
  3. expect.assertions(1);
  4. const data = await user.getUserName(4);
  5. expect(data).toEqual('Mark');
  6. });
  7. // async/await 也可以和 `.resolves` 一起使用.
  8. it('works with async/await and resolves', async () => {
  9. expect.assertions(1);
  10. await expect(user.getUserName(5)).resolves.toEqual('Paul');
  11. });

要在项目中启用 ​async​/​await​,请在你的​babel.config.js​文件中安装并启用@babel/preset-env功能。

错误处理

可以使用​ .catch​ 方法处理错误。 请确保添加 ​expect.assertions​ 来验证一定数量的断言被调用。 否则一个fulfilled态的Promise 不会让测试失败︰

  1. //用 Promise.catch 测试一个异步的错误
  2. it('tests error with promises', () => {
  3. expect.assertions(1);
  4. return user.getUserName(2).catch(e =>
  5. expect(e).toEqual({
  6. error: 'User with 2 not found.',
  7. }),
  8. );
  9. });
  10. // Or using async/await.
  11. it('tests error with async/await', async () => {
  12. expect.assertions(1);
  13. try {
  14. await user.getUserName(1);
  15. } catch (e) {
  16. expect(e).toEqual({
  17. error: 'User with 1 not found.',
  18. });
  19. }
  20. });

.rejects

该​.rejects​助手的工作方式类似于​.resolves​帮手。如果 Promise 被拒绝,则测试将自动失败。​expect.assertions(number)​不是必需的,但建议验证在测试期间调用了一定数量的assertions。其实不然容易忘记​return​/​await​的​.resolves​ ​assertions​。

  1. // 用`.rejects`.来测试一个异步的错误
  2. it('tests error with rejects', () => {
  3. expect.assertions(1);
  4. return expect(user.getUserName(3)).rejects.toEqual({
  5. error: 'User with 3 not found.',
  6. });
  7. });
  8. // 或者与async/await 一起使用 `.rejects`.
  9. it('tests error with async/await and rejects', async () => {
  10. expect.assertions(1);
  11. await expect(user.getUserName(3)).rejects.toEqual({
  12. error: 'User with 3 not found.',
  13. });
  14. });

此示例的代码位于examples/async

如果想测试计时器,例如setTimeout,请查看计时器模拟文档。