是否可以开玩笑地模拟从模块内部调用的函数?
Is it possible to mock a function called from inside module in 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() 在您的示例中绕过了模拟,因为有两个名称空间:模块和导出对象。当对 bar() 的引用被解析时 JavaScript 并且 TypeScript 在模块命名空间中搜索它,但 Jest 只能监视导出对象而不能更改模块的内容。
一种可能的解决方案是通过导出对象显式查找要模拟的标识符,如上所示。
我在这里找到了这个方法:https://medium.com/welldone-software/jest-how-to-mock-a-function-call-inside-a-module-21c05c57a39f#576f
试试这个重构:
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");
});
命名空间问题已通过这种方式解决
我有一个带有两个函数的 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() 在您的示例中绕过了模拟,因为有两个名称空间:模块和导出对象。当对 bar() 的引用被解析时 JavaScript 并且 TypeScript 在模块命名空间中搜索它,但 Jest 只能监视导出对象而不能更改模块的内容。
一种可能的解决方案是通过导出对象显式查找要模拟的标识符,如上所示。
我在这里找到了这个方法:https://medium.com/welldone-software/jest-how-to-mock-a-function-call-inside-a-module-21c05c57a39f#576f
试试这个重构:
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");
});
命名空间问题已通过这种方式解决