跳转至主内容
版本:29.7

绕过模块模拟

Jest允许在测试用例中模拟整个模块。这对于你测试被测代码是否正常调用某个模块的函数是很有用的。 However, sometimes you may want to use parts of a mocked module in your test file, in which case you want to access the original implementation, rather than a mocked version.

Consider writing a test case for this createUser function:

createUser.js
import fetch from 'node-fetch';

export const createUser = async () => {
const response = await fetch('https://website.com/users', {method: 'POST'});
const userId = await response.text();
return userId;
};

Your test will want to mock the fetch function so that we can be sure that it gets called without actually making the network request. However, you'll also need to mock the return value of fetch with a Response (wrapped in a Promise), as our function uses it to grab the created user's ID. 因此,你可以尝试编写这样的测试:

jest.mock('node-fetch');

import fetch, {Response} from 'node-fetch';
import {createUser} from './createUser';

test('createUser calls fetch with the right args and returns the user id', async () => {
fetch.mockReturnValue(Promise.resolve(new Response('4')));

const userId = await createUser();

expect(fetch).toHaveBeenCalledTimes(1);
expect(fetch).toHaveBeenCalledWith('https://website.com/users', {
method: 'POST',
});
expect(userId).toBe('4');
});

However, if you ran that test you would find that the createUser function would fail, throwing the error: TypeError: response.text is not a function. This is because the Response class you've imported from node-fetch has been mocked (due to the jest.mock call at the top of the test file) so it no longer behaves the way it should.

To get around problems like this, Jest provides the jest.requireActual helper. 要使上述测试用例工作,请对测试文件中导入的内容做如下更改:

// 修改前
jest.mock('node-fetch');
import fetch, {Response} from 'node-fetch';
// 修改后
jest.mock('node-fetch');
import fetch from 'node-fetch';
const {Response} = jest.requireActual('node-fetch');

This allows your test file to import the actual Response object from node-fetch, rather than a mocked version. 意味着测试用例现在将正确通过。