SpyOn单独导出ES6功能

时间:2018-03-08 12:55:09

标签: javascript unit-testing ecmascript-6 jasmine

TL; DR:

  1. 我使用 Jasmine ;
  2. 我想测试同一个名为aaa的{​​{1}}函数 模块;
  3. 我想监视bbb,但最终bbb打电话给aaa     原始bbb功能,而不是间谍;
  4. 如何强制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。我不想更改模块的代码,因为在这种情况下,我必须更改项目中的大量代码。我需要一个通用的测试解决方案。

2 个答案:

答案 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模块。

如果aaabbb位于不同的模块中,则可能更容易实现。这样就可以模拟模块(这不适用于本机ES模块)。