Je voudrais changer l'implémentation d'une dépendance simulée sur une base de test unique en étendant le comportement de la maquette par défaut et en le rétablissant à l'implémentation d'origine lorsque le prochain test s'exécute.
Plus brièvement, voici ce que j'essaie de réaliser:
- dépendance simulée
- modifier / étendre l'implémentation fictive en un seul test
- revenir à la maquette d'origine lors de l'exécution du prochain test
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 effects
});
it('should revert back to default myMockedModule mock', () => {
myMockedModule.a(); // === true
myMockedModule.b(); // === true
});
});
Voici ce que j'ai essayé jusqu'à présent:
1 - mockFn.mockImplementationOnce (fn)
avantages
- Revenir à l'implémentation d'origine après le premier appel
les inconvénients
- Il casse si le test appelle
b
plusieurs fois - Il ne revient pas à l'implémentation d'origine tant qu'il
b
n'est pas appelé (fuite lors du test suivant)
code:
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 (nom du module, usine, options)
avantages
- Se moque explicitement à chaque test
les inconvénients
- Impossible de définir l'implémentation fictive par défaut pour tous les tests
- Impossible d'étendre l'implémentation par défaut forçant à re-déclarer chaque méthode simulée
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'
});
3 - Mocking manuel avec des méthodes de setter (comme expliqué ici )
avantages
- Contrôle total des résultats simulés
les inconvénients
- Lot de code passe-partout
- Difficile à maintenir à long terme
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();
});
4 - jest.spyOn (objet, methodName)
les inconvénients
- Je ne peux pas revenir
mockImplementation
à la valeur de retour simulée d'origine, ce qui affecte les tests suivants
code:
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?
});