如何在 Jest 的 react-native 中使用模拟的 fetch() 对 API 调用进行单元测试

How to unit test API calls with mocked fetch() in react-native with Jest

在 React Native 中,我使用 fetch 来执行网络请求,但是 fetch 不是明确要求的模块,因此在 Jest 中似乎无法模拟。

即使尝试在测试中调用使用 fetch 的方法也会导致:

ReferenceError: fetch is not defined

有没有办法在 Jest 的 React Native 中测试这样的 API 请求?

在您的测试用例中,您可以使用 Jest 的模拟来模拟您想要的任何函数:

fetch = jest.fn(() => Promise.resolve());

此方法仅适用于基于承诺的测试用例(请参阅 Jest 文档中的 pit)。

至于 fetch 是一个异步函数,您需要使用 pit 运行 所有测试(阅读有关异步测试的更多信息 here)。

您可以使用 jest-fetch-mock npm 包覆盖全局获取对象,而不是滚动您自己的模拟。该软件包允许您设置虚假响应并验证发送的请求。请参阅 link 以获取大量使用示例。

模拟全局 fetch 对象的另一种方法:

const mockSuccesfulResponse = (
  status = 200,
  method = RequestType.GET,
  returnBody?: object
) => {
  global.fetch = jest.fn().mockImplementationOnce(() => {
    return new Promise((resolve, reject) => {
      resolve({
        ok: true,
        status,
        json: () => {
          return returnBody ? returnBody : {};
        },
      });
    });
  });
};

上面的辅助方法可以随意修改 :-) 希望对大家有帮助

我通过添加 isomorphic-fetch.

解决了这个问题
$ npm install --save isomorphic-fetch

并像

一样使用它
import fetch from 'isomorphic-fetch';
...
fetch('http://foo.com');

whatwg-fetch 也可以工作

正如@ArthurDenture 所推荐的那样,您可以使用 fetch-mock,但是您需要安装一些额外的包才能使其与 React Native 和 Jest 一起使用:

$ npm install --save-dev fetch-mock
$ npm install --save-dev babel-plugin-transform-runtime
$ npm install --save-dev babel-preset-env

然后您可以在测试中模拟提取请求。这是一个例子:

// __tests__/App.test.js
import React from 'react';
import App from '../App';
import fetchMock from 'fetch-mock';
import renderer from 'react-test-renderer';

it('renders without crashing', () => {
  fetchMock.mock('*', 'Hello World!');
  const rendered = renderer.create(<App />).toJSON();
  expect(rendered).toBeTruthy();
});

假设你想测试 resolve 和 reject 案例,为此你首先模拟获取行为,然后使用 Jestrejects 解决方法与断言块


function fetchTodos() {
  return fetch(`${window.location.origin}/todos.json`)
    .then(response => response.json())
    .catch(error => console.log(error))
}
describe('fetchTodos', () => {
  it('returns promise resolving to parsed response', () => {
    global.fetch = jest.fn(() => Promise.resolve({ json: () => ''}))
    expect(fetchTodos()).resolves.toBe('');
  })
  it('returns promise handling the error', async () => {
    global.fetch = jest.fn(() => Promise.reject(''))
    expect(fetchTodos()).rejects.toBe('')
  })
})

如 react-testing-library 文档所示,您可以使用 jest.spyOn() 函数,它只会在下次调用时模拟 fetch 函数。

const fakeUserResponse = {token: 'fake_user_token'}
jest.spyOn(window, 'fetch').mockImplementationOnce(() => {
  return Promise.resolve({
    json: () => Promise.resolve(fakeUserResponse),
  })
})

react-testing-library

由于将 fetch-mock 与 jest 一起使用时出现问题,我发布了 fetch-mock-jest. It basically gives the full fetch-mock api,但带有一些 jest 特定的助手,并且开箱即用,无需进行任何棘手的接线你自己