enhetstesting - Hvordan kan jeg mocke en eksportert typescript-funksjon i en jasmine-test?
Jeg prøver å mocke en funksjon eksportert fra en TypeScript-fil i en Jasmine-test. Jeg forventer at følgende skal mocke den importerte foo og returnere verdien 1 i spesifikasjonen for bar.
Mocken ser ut til å være ukalt, så jeg mangler tydeligvis noe. Hvordan kan jeg fikse dette eksemplet?
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();
});
});
Feil:
- Forventet at 4 skulle være lik 3.
- Forventet at spionen foo hadde blitt kalt.
Svar #1
Jefferys svar hjalp meg med å komme på rett spor.
For å feste spionen til høyre referanse for foo må produktkoden ha en liten endring. foo() bør kalles som this.foo()
Mønsteret nedenfor fungerer for testing (og er mye renere enn den innviklede løsningen jeg brukte tidligere).
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();
});
});
Svar #2
Fra dette problemet på Github: Hvordan forventer du å bruke den overvåkede funksjonen i din faktiske implementering?
Din bar-implementering kaller den faktiske implementeringen av foo, fordi den har en direkte referanse til den. Når du importerer i en annen modul, opprettes et nytt objekt, med nye referanser:
// This creates a new object { foo: ..., bar: ... }
import * as demo from './demo';
Disse referansene eksisterer kun i modulen til importen. Når du kaller spyOn(demo, 'foo') er det den referansen som brukes. Du kan prøve dette i din spesifikasjon, sjansen er stor for at testen passerer:
demo.foo();
expect(demo.foo).toHaveBeenCalled();
Å forvente at den faktiske implementeringen av bar kaller en mocket foo er egentlig ikke mulig. I stedet bør du prøve å behandle bar som om den hadde sin egen implementering av foo.
