TL; DR:
aaa
的{{1}}函数
模块; bbb
,但最终bbb
打电话给aaa
原始bbb
功能,而不是间谍; 如何强制aaa
致电间谍?
模块:
export function aaa() {
return bbb();
}
export function bbb() {
return 222;
}
测试:
import * as util from 'my-module';
describe('aaa test', () => {
let bbbSpy: Spy;
beforeEach(() => {
bbbSpy = spyOn(util, 'bbb');
});
it('should return SPYED', () => {
bbbSpy.and.returnValue('SPYED!!');
const result = util.aaa();
expect(result).toEqual('SPYED!!'); // Doesn't work - still 222
});
});
所以,基本上这不起作用。有人可以帮帮我吗?
P.S。我不想更改模块的代码,因为在这种情况下,我必须更改项目中的大量代码。我需要一个通用的测试解决方案。
答案 0 :(得分:4)
即使思想不是同一个框架,也有一个相关的问题可以解释为什么这不起作用:How to mock functions in the same module using jest。基本上你不能访问函数的这个固定引用,而是明确表示与模块上下文中的函数相同。
我知道这不符合您在问题中发布的约束,但是很明显,使用间谍无法实现您想要实现的目标。
使用JavaScript,无法将引用换成某些东西。您无法交换模块内部的功能。当您尝试在示例中使用spyOn.and.returnValue覆盖bbb时,您只是在测试中修改本地绑定bbb,但它对您的其他文件中的bbb绑定没有影响。
答案 1 :(得分:2)
代码并没有考虑到测试问题,如果没有重构,它将无法完全覆盖。
在这种情况下,强制aaa
强制调用间谍是不可能的。它直接引用模块范围中的bbb
函数。没有任何对象可以窥探。
它基本上与JavaScript范围问题相同:
(() => {
var bar = 1; // there's no way to reach this variable from the outside
})();
如果函数一直被称为对象属性,则可以这样做。 ES模块中没有这样的对象,但这个配方在CommonJS模块中很常见,特别是因为可测试性问题(像Webpack这样的捆绑工具):
exports.aaa = function aaa() {
return exports.bbb();
}
exports.bbb = function bbb() {
return 222;
}
这种bbb
属性可以*
使用spyOn(util, 'bbb')
导入,如原始代码所示。这不适用于具有只读导出且不与CommonJS模块互操作的本机ES模块。
如果aaa
和bbb
位于不同的模块中,则可能更容易实现。这样就可以模拟模块(这不适用于本机ES模块)。