如何在jasmine测试中模拟导出的typescript函数?

时间:2018-03-28 15:27:02

标签: unit-testing typescript jasmine mocking spy

我试图在Jasmine测试中模拟从typescript文件导出的函数。我希望以下内容模拟导入的foo并在规范栏中返回值1。

模拟似乎是不必要的,所以我明显遗漏了一些东西。我该如何修复这个例子?

demo.ts:

export function foo(input: any): any {
  return 2;
}

export function bar(input: any): any {
  return foo(input) + 2;
}

demo.ts.spec:

import * as demo from './demo';

describe('foo:', () => {
  it('returns 2', () => {
    const actual = demo.foo(1);
    expect(actual).toEqual(2);
  });
});

describe('bar:', () => {
  // let fooSpy;
  beforeEach(() => {
    spyOn(demo, 'foo' as any).and.returnValue(1); // 'as any' prevents compiler warning
  });

  it('verifies that foo was called', () => {
    const actual = demo.bar(1);
    expect(actual).toEqual(3); // mocked 1 + actual 2
    expect(demo.foo).toHaveBeenCalled();
  });
});

故障:

  • 预计4等于3。
  • 预计会被调用的间谍foo。

2 个答案:

答案 0 :(得分:3)

  

来自this issue on Github:你期望在实际实现中使用spied on函数吗?

您的bar实现会调用foo实际实现,因为它直接引用它。在另一个模块中导入时,会创建一个带有新引用的新对象:

// This creates a new object { foo: ..., bar: ... }
import * as demo from './demo';

这些引用仅存在于导入模块中。当您致电spyOn(demo, 'foo')时,它正在使用该引用。你可能想在你的规范中尝试这个,测试通过的可能性很小:

demo.foo();
expect(demo.foo).toHaveBeenCalled();

期望真正实现bar来调用模拟的foo实际上是不可能的。相反,请尝试将bar视为具有自己的foo实现。

答案 1 :(得分:1)

杰弗瑞的回答帮助我走上正轨。

要附加间谍附加到firebase.database().ref(this.getUserPath('/savedQuoteList')).once("value") .then(function(snapshot) { console.log(snapshot.numChildren()); if(snapshot.numChildren()<3){ this.angularFireDatabase.list(this.getUserPath('/savedQuoteList')).push(q); console.log("Quote saved."); }else { console.log("Too many quotes in list."); } }); 的右侧参考,产品代码需要进行少量更改。 foo应该被称为foo()

以下模式适用于测试(并且比我之前使用的复杂工作更清晰。)

demo.ts:

this.foo()

demo.ts.spec:

export function foo(input: any): any {
  return 2;
}

export function bar(input: any): any {
  return this.foo(input) + 2;
}