Chciałbym zmienić implementację mockowanej zależności na podstawie pojedynczego testu , rozszerzając domyślne zachowanie makiety i przywracając ją z powrotem do oryginalnej implementacji, gdy wykonywany jest następny test.
W skrócie to, co staram się osiągnąć:
- pozorowana zależność
- zmień / rozszerz próbną implementację w jednym teście
- powrócić do oryginalnego makiety po wykonaniu następnego testu
Obecnie używam Jest v21
.
Oto jak wyglądałby typowy test Jest:
__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 effects
});
it('should revert back to default myMockedModule mock', () => {
myMockedModule.a(); // === true
myMockedModule.b(); // === true
});
});
Oto, czego próbowałem do tej pory:
1 - mockFn.mockImplementationOnce (fn)
plusy
- Przywraca pierwotną implementację po pierwszym wywołaniu
Cons
- Zepsuje się, jeśli test wywoła
b
wiele razy - Nie powraca do oryginalnej implementacji, dopóki
b
nie zostanie wywołana (wyciek w następnym teście)
kod:
it('should override myModule.b mock result (and leave the other methods untouched)', () => {
myMockedModule.b.mockImplementationOnce(() => 'overridden');
myModule.a(); // === true
myModule.b(); // === 'overridden'
});
2 - jest.doMock (nazwa modułu, fabryka, opcje)
plusy
- Wyraźnie ponownie kpi z każdego testu
Cons
- Nie można zdefiniować domyślnej implementacji próbnej dla wszystkich testów
- Nie można rozszerzyć domyślnej implementacji wymuszającej ponowne zadeklarowanie każdej mockowanej metody
kod:
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'
});
3 - Ręczne mockowanie metodami ustawiającymi (jak wyjaśniono tutaj )
plusy
- Pełna kontrola nad fałszywymi wynikami
Cons
- Dużo kodu standardowego
- Trudne do utrzymania przez dłuższy czas
kod:
__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();
});
4 - jest.spyOn (obiekt, nazwa metody)
Cons
- Nie mogę powrócić
mockImplementation
do pierwotnej wartości zwracanej, co ma wpływ na następne testy
kod:
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 original mocked value?
});
javascript
unit-testing
mocking
jestjs
Andrea Carraro
źródło
źródło
Odpowiedzi:
Przyjemnym wzorcem do pisania testu jest utworzenie funkcji ustawień fabrycznych, która zwraca dane potrzebne do przetestowania bieżącego modułu.
Poniżej znajduje się przykładowy kod następujący po drugim przykładzie, chociaż umożliwia dostarczanie wartości domyślnych i zastępowanie wartości w sposób wielokrotnego użytku.
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) }); });
źródło
Vanilla JS
Użyj mockFn.mockImplementation (fn) .
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 */ }); // ... });
Maszynopis
Aby zapobiec wyświetlaniu wiadomości mockImplementation nie jest właściwością funcToMock , będziesz musiał określić typ, np. Zmieniając górną linię z góry na następującą:
import { (funcToMock as jest.Mock) } from './somewhere';
Pytanie dotyczące tego problemu można znaleźć tutaj: jest to makieta właściwości maszynopisu nie istnieje w typie
źródło
Trochę późno na imprezę, ale jeśli ktoś ma z tym problem.
Używamy TypeScript, ES6 i Babel do tworzenia natywnych rozwiązań.
Zwykle mockujemy zewnętrzne moduły NPM w
__mocks__
katalogu głównym .Chciałem zastąpić określoną funkcję modułu w klasie Auth aws-amplify dla określonego testu.
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(); });
Streszczenie: https://gist.github.com/thomashagstrom/e5bffe6c3e3acec592201b6892226af2
Samouczek: https://medium.com/p/b4ac52a005d#19c5
źródło