是否可以在jest中模拟从模块内部调用的函数?



我有一个带有两个函数的TypeScript模块:foo()调用bar()。我想模拟bar()并从单元测试中调用foo()。我试过了:

foo.ts:

export function bar(){
throw 'not implemented'
}
export function foo(){
return bar();
}

foo.test.ts:

import * as foo from './foo'
test('TODO', () => {
jest.spyOn(foo, 'bar').mockReturnValue('quux')
expect(foo.foo()).toBe('quux')
});

但是我得到了一个错误:

FAIL  ./foo.test.ts
✕ TODO (4 ms)
● TODO
thrown: "not implemented"
1 | import * as foo from './foo'
2 |
> 3 | test('TODO', () => {
| ^
4 |   jest.spyOn(foo, 'bar').mockReturnValue('quux')
5 |   expect(foo.foo()).toBe('quux')
6 | });
at Object.<anonymous> (foo.test.ts:3:1)
at TestScheduler.scheduleTests (node_modules/@jest/core/build/TestScheduler.js:333:13)

似乎foo()以某种方式绕过了模拟。我如何使它使用模拟而不是真正的bar()?

修改foo()调用exports.bar()而不是bar():

export function foo(){
return exports.bar();
}

示例中的foo()绕过了mock,因为有两个名称空间:模块和exports对象。当对bar()的引用被解析后,JavaScript和TypeScript会在模块命名空间中搜索它,但Jest只能监视exports对象,不能改变模块的内容。

一种可能的解决方案是通过如上所示的exports对象显式查找要模拟的标识符。

我在这里找到了这个方法:https://medium.com/welldone-software/jest-how-to-mock-a-function-call-inside-a-module-21c05c57a39f#576f

try this refactor:

foo.ts:

const fn = {
bar(): unknown | void {
throw "not implemented";
},
foo() {
return fn.bar();
},
};
export default fn

foo.test.ts:

import functionsUnderTest from "./foo";
beforeEach(() => {
jest.spyOn(functionsUnderTest, "bar").mockReturnValue("quux");
});
test("TODO", () => {
expect(functionsUnderTest.foo()).toBe("quux");
});

名称空间的问题通过这种方式解决

相关内容

  • 没有找到相关文章

最新更新