使用 Jest 模拟同一模块中的函数
在同一模块中模拟函数时,了解 Jest 默认模拟的局限性至关重要
问题:
导入模块并直接模拟其导出的函数(如下例所示)可能会导致意外行为。
// module.js export function bar() { return 'bar'; } export function foo() { return `I am foo. bar is ${bar()}`; } // module.test.js import * as module from '../src/module'; describe('module', () => { let barSpy; beforeEach(() => { barSpy = jest.spyOn(module, 'bar').mockImplementation(jest.fn()); }); it('foo', () => { module.bar.mockReturnValue('fake bar'); expect(module.foo()).toEqual('I am foo. bar is fake bar'); // Fails: Expected "I am foo. bar is fake bar" but received "I am foo. bar is bar" }); });
说明:
以上例如, foo 在导入期间直接调用原始 bar 函数。即使 barSpy 在测试设置期间正确更新,foo 仍然引用未模拟的 bar 函数,导致输出不正确。
解决方案 1:
导入模块进入其自己的代码文件:
要避免此问题,模块可以导入到自己的代码文件中,确保所有导出的实体都是从同一个实例导入的。
// module.js export function bar() { return 'bar'; } export function foo() { return `I am foo. bar is ${thisModule.bar()}`; } // module.test.js import * as module from './module'; describe('module', () => { it('foo', () => { spyOn(module, 'bar').and.returnValue('fake bar'); expect(module.foo()).toEqual('I am foo. bar is fake bar'); }); });
在此修改后的示例中,foo 现在通过导入的实例 module.bar 访问 bar,从而可以轻松进行模拟。
解决方案 2:
手动模拟导入:
或者,可以在测试设置中手动模拟导入,创建与未模拟版本隔离的模块的新实例。
// module.test.js jest.mock('../src/module'); const * as mockedModule = require('../src/module'); describe('module', () => { beforeEach(() => { mockedModule.bar.mockImplementation(jest.fn()); }); it('foo', () => { mockedModule.bar.mockReturnValue('fake bar'); expect(mockedModule.foo()).toEqual('I am foo. bar is fake bar'); }); });
在此方法中,使用模拟实例mockedModule进行测试,防止来自未模拟导入的干扰。
以上是如何使用 Jest 有效模拟同一模块内的函数?的详细内容。更多信息请关注PHP中文网其他相关文章!