Je voudrais modifier la mise en œuvre d'une dépendance moquée sur une base de test unique en étendant le comportement par défaut du mock et en le ramenant à la mise en œuvre d'origine lorsque le test suivant s'exécute.
Plus brièvement, voici ce que j'essaie d'accomplir :
- Mocker la dépendance
- Modifier/étendre la mise en œuvre du mock dans un seul test
- Revenir à la mise en œuvre initiale du mock lorsque le test suivant s'exécute
Je utilise actuellement Jest v21. Voici à quoi ressemblerait un test 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('devrait tester avec le mock par défaut', () => {
myMockedModule.a(); // === true
myMockedModule.b(); // === true
});
it('devrait remplacer le résultat du mock myMockedModule.b (et laisser les autres méthodes intactes)', () => {
// Étendre le changement du mock
myMockedModule.a(); // === true
myMockedModule.b(); // === 'surchargé'
// Restaurer le mock à la mise en œuvre d'origine sans effets secondaires
});
it('devrait revenir au mock par défaut de myMockedModule', () => {
myMockedModule.a(); // === true
myMockedModule.b(); // === true
});
});
Voici ce que j'ai essayé jusqu'à présent :
-
mockFn.mockImplementationOnce(fn)
it('devrait remplacer le résultat du mock myModule.b (et laisser les autres méthodes intactes)', () => { myMockedModule.b.mockImplementationOnce(() => 'surchargé'); myModule.a(); // === true myModule.b(); // === 'surchargé' });
Avantages
- Reviens à la mise en œuvre d'origine après le premier appel
Inconvénients
- Il casse si le test appelle
b
plusieurs fois - Il ne revient pas à la mise en œuvre originale tant que
b
n'est pas appelé (fuite dans le test suivant)
-
jest.doMock(moduleName, factory, options)
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' });
Avantages
- Re-mocks explicitement à chaque test
Inconvénients
- Impossible de définir une mise en œuvre par défaut pour tous les tests
- Impossible d'étendre l'implémentation par défaut obligeant à redéclarer chaque méthode moquée
-
Mocking manuel avec des méthodes setter (comme expliqué ici)
// __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('devrait remplacer le résultat du mock myModule.b (et laisser les autres méthodes intactes)', () => { myModule.__setB('surchargé'); myModule.a(); // === true myModule.b(); // === 'surchargé' myModule.__reset(); });
Avantages
- Contrôle total sur les résultats moqués
Inconvénients
- Beaucoup de code redondant
- Difficile à maintenir à long terme
-
jest.spyOn(object, methodName)
beforeEach(() => { jest.clearAllMocks(); jest.restoreAllMocks(); }); // Mock myModule jest.mock('../myModule'); it('devrait remplacer le résultat du mock myModule.b (et laisser les autres méthodes intactes)', () => { const spy = jest.spyOn(myMockedModule, 'b').mockImplementation(() => 'surchargé'); myMockedModule.a(); // === true myMockedModule.b(); // === 'surchargé' // Comment revenir à la valeur moquée d'origine ? });
Inconvénients
- Je ne peux pas revenir à
mockImplementation
à la valeur de retour moquée d'origine, affectant donc les tests suivants
- Je ne peux pas revenir à
1 votes
Bien. Mais comment faites-vous l'option 2 pour un module npm comme '@private-repo/module'? La plupart des exemples que je vois ont des chemins relatifs? Est-ce que cela fonctionne aussi pour les modules installés?