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?
});
javascript
unit-testing
mocking
jestjs
Andrea Carraro
la source
la source
Réponses:
Un bon modèle pour le test d'écriture est de créer une fonction de fabrique de configuration qui renvoie les données dont vous avez besoin pour tester le module actuel.
Vous trouverez ci-dessous un exemple de code suivant votre deuxième exemple, bien qu'il autorise la fourniture de valeurs par défaut et 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) }); });
la source
Vanille JS
Utilisez 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 */ }); // ... });
Manuscrit
Pour éviter que le message mockImplementation ne soit une propriété de funcToMock , vous devrez spécifier le type, par exemple en changeant la ligne supérieure de ci-dessus à la suivante:
import { (funcToMock as jest.Mock) } from './somewhere';
Une question traitant de ce problème peut être trouvée ici: la propriété jest dactylographiée mock n'existe pas sur le type
la source
Un peu tard à la fête, mais si quelqu'un d'autre a des problèmes avec ça.
Nous utilisons TypeScript, ES6 et babel pour le développement natif de réaction.
Nous nous moquons généralement des modules NPM externes dans le
__mocks__
répertoire racine .Je voulais remplacer une fonction spécifique d'un module dans la classe Auth de 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
la source