J'aimerais modifier modifier l'implémentation d'une dépendance simuléesur un base de test uniquepar étendre le comportement par défaut de mocket srevenir à l'implémentation d'originelorsque le test suivant s'exécute.
Plus brièvement c'est ce que j'essaie de réaliser:
J'utilise actuellement Jest v21
.
Voici à quoi ressemblerait un test Jest typique:
__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
});
});
J'ai essayé quelques stratégies, mais je n'ai trouvé aucune solution que je puisse définir satisfaisante.
pros
contre
b
plusieurs foisb
n'aura pas été appelée (fuite lors du prochain 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'
});
pros
contre
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'
});
pros
contre
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();
});
contre
mockImplementation
à la valeur de retour fictive d'origine, ce qui affecte les tests suivantscode:
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?
});
Merci d'avance pour toute contribution/suggestion!
Un bon modèle pour le test d’écriture consiste à créer une fonction d’usine d’installation qui renvoie les données nécessaires au test du module actuel.
Vous trouverez ci-dessous un exemple de code qui suit votre deuxième exemple, bien qu'il permette de fournir des valeurs par défaut et des valeurs de remplacement de manière réutilisable.
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)
})
});
Un peu tard pour la fête, mais si quelqu'un d'autre a des problèmes avec cela.
Nous utilisons TypeScript, ES6 et babel pour le développement réactif natif.
Nous modifions généralement les modules NPM externes dans le répertoire racine __mocks__
.
Je voulais remplacer une fonction spécifique d'un module de la classe Auths aws-amplify pour un test spécifique.
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
Tutoriel: https://medium.com/p/b4ac52a005d#19c5
Utilisez mockFn.mockImplementation (fn) .
Mettez l'implémentation par défaut dans la beforeEach
. La maquette sera réinitialisée à cela avant chaque test.
Pour remplacer, utilisez mockImplementation
dans le test.
Cela annulera le comportement de la maquette pour tous les appels du test et sera écrasé par l'implémentation beforeEach
avant le prochain test.
Par exemple:
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 */ });
// ...
});