问题
I'm trying to mock a function exported from a typescript file in a Jasmine test. I expect the following to mock the imported foo
and return the value 1 in the spec for bar.
The mock appears to be uncalled, so I'm clearly missing something. How can I fix this example?
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();
});
});
Failures:
- Expected 4 to equal 3.
- Expected spy foo to have been called.
回答1:
From this issue on Github: How are you expecting to use the spied on function in your actual implementation?
Your bar
implementation calls the actual implementation of foo
, because it has a direct reference to it. When importing in another module, a new object, with new references, is created:
// This creates a new object { foo: ..., bar: ... }
import * as demo from './demo';
These references exist only in the module of the import. When you call spyOn(demo, 'foo')
it's that reference that is being used. You might want to try this in your spec, chances are the test passes:
demo.foo();
expect(demo.foo).toHaveBeenCalled();
Expecting the real implementation of bar
to call a mocked foo
is not really possible. Instead try to treat bar
as if it had its own implementation of foo
.
回答2:
Jeffery's answer helped get me on the right track.
To attach the spy is attached to the right reference for foo
the product code needs to have a small change. foo()
should be called as this.foo()
The below pattern works for testing (and is a lot cleaner than the convoluted work around I was using previously).
demo.ts:
export function foo(input: any): any {
return 2;
}
export function bar(input: any): any {
return this.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);
});
it('verifies that foo was called', () => {
const actual = demo.bar(1);
expect(actual).toEqual(3);
expect(demo.foo).toHaveBeenCalled();
});
});
来源:https://stackoverflow.com/questions/49538472/how-do-i-mock-an-exported-typescript-function-in-a-jasmine-test