Ich möchte die Implementierung einer verspotteten Abhängigkeit ändern auf einer pro einzelnen Testbasis um das Verhalten der Standard-Verspottung erweitern und es rückgängig machen zurück zur ursprünglichen Implementierung, wenn der folgende Test ausgeführt wird.
Kurz gesagt, das versuche ich zu erreichen:
Ich verwende derzeit Jest v21
.
So würde ein typischer Scherztest aussehen:
__mocks__/myModule.js
const myMockedModule = jest.genMockFromModule('../myModule');
myMockedModule.a = jest.fn(() => true);
myMockedModule.b = jest.fn(() => true);
export default myMockedModule;
__tests__/myTest.js
import myMockedModule from '../myModule';
// Mock myModule
jest.mock('../myModule');
beforeEach(() => {
jest.clearAllMocks();
});
describe('MyTest', () => {
it('should test with default mock', () => {
myMockedModule.a(); // === true
myMockedModule.b(); // === true
});
it('should override myMockedModule.b mock result (and leave the other methods untouched)', () => {
// Extend change mock
myMockedModule.a(); // === true
myMockedModule.b(); // === 'overridden'
// Restore mock to original implementation with no side eeffects
});
it('should revert back to default myMockedModule mock', () => {
myMockedModule.a(); // === true
myMockedModule.b(); // === true
});
});
Ich habe ein paar Strategien ausprobiert, aber keine Lösung gefunden, die ich als zufriedenstellend bezeichnen könnte.
Profis
Nachteile
b
aufruftb
nicht aufgerufen wird (undicht im nächsten Test).Code:
it('should override myModule.b mock result (and leave the other methods untouched)', () => {
myMockedModule.b.mockImplementationOnce(() => 'overridden');
myModule.a(); // === true
myModule.b(); // === 'overridden'
});
Profis
Nachteile
Code:
it('should override myModule.b mock result (and leave the other methods untouched)', () => {
jest.doMock('../myModule', () => {
return {
a: jest.fn(() => true,
b: jest.fn(() => 'overridden',
}
});
myModule.a(); // === true
myModule.b(); // === 'overridden'
});
Profis
Nachteile
Code:
__mocks__/myModule.js
const myMockedModule = jest.genMockFromModule('../myModule');
let a = true;
let b = true;
myMockedModule.a = jest.fn(() => a);
myMockedModule.b = jest.fn(() => b);
myMockedModule.__setA = (value) => { a = value };
myMockedModule.__setB = (value) => { b = value };
myMockedModule.__reset = () => {
a = true;
b = true;
};
export default myMockedModule;
__tests__/myTest.js
it('should override myModule.b mock result (and leave the other methods untouched)', () => {
myModule.__setB('overridden');
myModule.a(); // === true
myModule.b(); // === 'overridden'
myModule.__reset();
});
Nachteile
mockImplementation
nicht auf den ursprünglichen verspotteten Rückgabewert zurücksetzen, was sich auf die folgenden Tests auswirktCode:
beforeEach(() => {
jest.clearAllMocks();
jest.restoreAllMocks();
});
// Mock myModule
jest.mock('../myModule');
it('should override myModule.b mock result (and leave the other methods untouched)', () => {
const spy = jest.spyOn(myMockedModule, 'b').mockImplementation(() => 'overridden');
myMockedModule.a(); // === true
myMockedModule.b(); // === 'overridden'
// How to get back to the original mocked value?
});
Vielen Dank im Voraus für jede Eingabe/Anregung!
Ein schönes Muster für den Schreibtest ist das Erstellen einer Setup-Factory-Funktion, die die Daten zurückgibt, die Sie zum Testen des aktuellen Moduls benötigen.
Nachfolgend finden Sie einige Beispielcodes, die Ihrem zweiten Beispiel folgen. Sie können jedoch Standardwerte und Überschreibungswerte wiederverwenden.
const spyReturns = returnValue => jest.fn(() => returnValue);
describe("scenario", () => {
const setup = (mockOverrides) => {
const mockedFunctions = {
a: spyReturns(true),
b: spyReturns(true),
...mockOverrides
}
return {
mockedModule: jest.doMock('../myModule', () => mockedFunctions);
}
}
it("should return true for module a", () => {
const {mockedModule} = setup();
expect(mockedModule.a()).toEqual(true)
});
it("should return override for module a", () => {
const EXPECTED_VALUE = "override"
const {mockedModule} = setup({ a: spyReturns(EXPECTED_VALUE)});
expect(mockedModule.a()).toEqual(EXPECTED_VALUE)
})
});
Etwas spät zur Party, aber wenn jemand anderes Probleme damit hat.
Wir verwenden TypeScript, ES6 und Babel für die reaktionsgenaue Entwicklung.
In der Regel machen wir externe NPM-Module im Stammverzeichnis __mocks__
nach.
Ich wollte eine bestimmte Funktion eines Moduls in der Auth-Klasse von aws-amplify für einen bestimmten Test überschreiben.
import { Auth } from 'aws-amplify';
import GetJwtToken from './GetJwtToken';
...
it('When idToken should return "123"', async () => {
const spy = jest.spyOn(Auth, 'currentSession').mockImplementation(() => ({
getIdToken: () => ({
getJwtToken: () => '123',
}),
}));
const result = await GetJwtToken();
expect(result).toBe('123');
spy.mockRestore();
});
Gist: https://Gist.github.com/thomashagstrom/e5bffe6c3e3acec592201b6892226af2
Lernprogramm: https://medium.com/p/b4ac52a005d#19c5
Verwenden Sie mockFn.mockImplementation (fn) .
Setzen Sie die Standardimplementierung in beforeEach
. Das Mock wird vor jedem Test darauf zurückgesetzt.
Verwenden Sie zum Überschreiben mockImplementation
im Test.
Dadurch wird das Verhalten des Modells für alle/alle Aufrufe im Test überschrieben und vor dem nächsten Test durch die beforeEach
-Implementierung überschrieben.
Zum Beispiel:
import { funcToMock } from './somewhere';
jest.mock('./somewhere');
beforeEach(() => {
funcToMock.mockImplementation(() => { /* default implementation */ });
});
test('case that needs a different implementation of funcToMock', () => {
funcToMock.mockImplementation(() => { /* implementation specific to this test */ });
// ...
});