Fonctions simulées
Les fonctions simulées sont également connues sous le nom d'« espions », car elles vous permettent d'espionner le comportement d'une fonction qui est appelée indirectement par un autre code, plutôt que de tester uniquement la sortie. Vous pouvez créer une fonction simulée avec jest.fn()
. Si aucune implémentation n’est donnée, la fonction simulée retournera undefined
lorsqu’elle est appelée.
Les exemples TypeScript de cette page ne fonctionneront comme documenté que si vous importez explicitement les API Jest :
import {expect, jest, test} from '@jest/globals';
Méthodes
- Référence
mockFn.getMockName()
mockFn.mock.calls
mockFn.mock.results
mockFn.mock.instances
mockFn.mock.contexts
mockFn.mock.lastCall
mockFn.mockClear()
mockFn.mockReset()
mockFn.mockRestore()
mockFn.mockImplementation(fn)
mockFn.mockImplementationOnce(fn)
mockFn.mockName(name)
mockFn.mockReturnThis()
mockFn.mockReturnValue(value)
mockFn.mockReturnValueOnce(value)
mockFn.mockResolvedValue(value)
mockFn.mockResolvedValueOnce(value)
mockFn.mockRejectedValue(value)
mockFn.mockRejectedValueOnce(value)
- TypeScript Usage
Référence
mockFn.getMockName()
Returns the mock name string set by calling .mockName()
.
mockFn.mock.calls
Un tableau contenant les arguments d'appel de tous les appels qui ont été faits à cette fonction simulée. Chaque élément du tableau est un tableau d'arguments qui ont été passés pendant l'appel.
Par exemple : Une fonction simulée f
qui a été appelée deux fois, avec les arguments f('arg1', 'arg2')
, puis avec les arguments f('arg3', 'arg4')
, aurait un tableau mock.calls
qui ressemble à ceci :
[
['arg1', 'arg2'],
['arg3', 'arg4'],
];
mockFn.mock.results
Un tableau contenant les résultats de tous les appels qui ont été faits à cette fonction simulée. Chaque entrée de ce tableau est un objet contenant une propriété type
, et une propriété value
. type
sera l'un des suivants :
'return'
- Indique que l'appel s'est terminé en retournant normalement.'throw'
- Indique que l'appel s'est terminé en levant une valeur.'incomplete'
- Indique que l'appel n'est pas encore terminé. Cela se produit si vous testez le résultat à partir de la fonction simulée elle-même, ou à partir d'une fonction qui a été appelée par la fonction simulée.
La propriété value
contient la valeur qui a été levée ou retournée. value
est indéfinie lorsque type === 'incomplete'
.
Par exemple : Une fonction simulée f
qui a été appelée trois fois, renvoyant 'result1'
, lançant une erreur, puis renvoyant 'result2'
, aurait un tableau mock.results
qui ressemble à ceci :
[
{
type: 'return',
value: 'result1',
},
{
type: 'throw',
value: {
/* Error instance */
},
},
{
type: 'return',
value: 'result2',
},
];
mockFn.mock.instances
Un tableau qui contient toutes les instances d'objet qui ont été instanciées à partir de cette fonction simulée en utilisant new
.
Par exemple : Une fonction simulée qui a été instanciée deux fois aurait le tableau mock.instances
suivant :
const mockFn = jest.fn();
const a = new mockFn();
const b = new mockFn();
mockFn.mock.instances[0] === a; // true
mockFn.mock.instances[1] === b; // true
mockFn.mock.contexts
Un tableau qui contient les contextes pour tous les appels de la fonction simulée.
Un contexte est la valeur this
qu'une fonction reçoit lorsqu'elle est appelée. Le contexte peut être défini en utilisant Function.prototype.bind
, Function.prototype.call
ou Function.prototype.apply
.
Par exemple :
const mockFn = jest.fn();
const boundMockFn = mockFn.bind(thisContext0);
boundMockFn('a', 'b');
mockFn.call(thisContext1, 'a', 'b');
mockFn.apply(thisContext2, ['a', 'b']);
mockFn.mock.contexts[0] === thisContext0; // true
mockFn.mock.contexts[1] === thisContext1; // true
mockFn.mock.contexts[2] === thisContext2; // true
mockFn.mock.lastCall
Un tableau contenant les arguments d'appel du dernier appel qui a été fait à cette fonction simulée. Si la fonction n'a pas été appelée, elle retournera undefined
.
Par exemple : Une fonction simulée f
qui a été appelée deux fois, avec les arguments f('arg1', 'arg2')
, puis avec les arguments f('arg3', 'arg4')
, aurait un tableau mock.lastCall
qui ressemble à ceci :
['arg3', 'arg4'];
mockFn.mockClear()
Efface toutes les informations stockées dans les tableaux mockFn.mock.calls
, mockFn.mock.instances
, mockFn.mock.contexts
et mockFn.mock.results
. Souvent, cela est utile lorsque vous voulez nettoyer les données d'utilisation d'une simulation entre deux assertions.
L'option de configuration clearMocks
est disponible pour effacer les simulations automatiquement avant chaque test.
Attention, mockFn.mockClear()
remplacera mockFn.mock
, et ne se contentera pas de réinitialiser les valeurs de ses propriétés ! Vous devriez donc éviter d'assigner mockFn.mock
à d'autres variables, temporaires ou non, pour être sûr de ne pas accéder à des données périmées.
mockFn.mockReset()
Fait tout ce que mockFn.mockClear()
fait, et supprime également toute valeur de retour ou d'implémentation simulées.
Ceci est utile lorsque vous voulez réinitialiser complètement une simulation à son état initial.
The resetMocks
configuration option is available to reset mocks automatically before each test.
Resetting a mock created with jest.spyOn()
will result in a function with no return value.
mockFn.mockRestore()
Fait tout ce que mockFn.mockReset()
fait, et restaure également l'implémentation originale (non simulée).
Ceci est utile lorsque vous voulez simuler des fonctions dans certains cas de test et restaurer l'implémentation originale dans d'autres.
L'option de configuration restoreMocks
est disponible pour restaurer les simulations automatiquement avant chaque test.
mockFn.mockRestore()
only works when the mock was created with jest.spyOn()
. Vous devez donc vous occuper vous-même de la restauration lorsque vous assignez manuellement jest.fn()
.
mockFn.mockImplementation(fn)
Accepte une fonction qui doit être utilisée comme l'implémentation de simulation. La simulation elle-même enregistrera toujours tous les appels qui entrent et les instances qui proviennent d'elle - la seule différence est que l'implémentation sera également exécutée lorsque la simulation est appelée.
jest.fn(implémentation)
est un raccourci pour jest.fn().mockImplementation(implémentation)
.
- JavaScript
- TypeScript
const mockFn = jest.fn(scalar => 42 + scalar);
mockFn(0); // 42
mockFn(1); // 43
mockFn.mockImplementation(scalar => 36 + scalar);
mockFn(2); // 38
mockFn(3); // 39
import {jest} from '@jest/globals';
const mockFn = jest.fn((scalar: number) => 42 + scalar);
mockFn(0); // 42
mockFn(1); // 43
mockFn.mockImplementation(scalar => 36 + scalar);
mockFn(2); // 38
mockFn(3); // 39
.mockImplementation()
peut également être utilisé pour simuler les constructeurs de classes :
- JavaScript
- TypeScript
module.exports = class SomeClass {
method(a, b) {}
};
const SomeClass = require('./SomeClass');
jest.mock('./SomeClass'); // cela se produit automatiquement avec l'auto-simulation
const mockMethod = jest.fn();
SomeClass.mockImplementation(() => {
return {
method: mockMethod,
};
});
const some = new SomeClass();
some.method('a', 'b');
console.log('Calls to method: ', mockMethod.mock.calls);
export class SomeClass {
method(a: string, b: string): void {}
}
import {jest} from '@jest/globals';
import {SomeClass} from './SomeClass';
jest.mock('./SomeClass'); // this happens automatically with automocking
const mockMethod = jest.fn<(a: string, b: string) => void>();
jest.mocked(SomeClass).mockImplementation(() => {
return {
method: mockMethod,
};
});
const some = new SomeClass();
some.method('a', 'b');
console.log('Calls to method: ', mockMethod.mock.calls);
mockFn.mockImplementationOnce(fn)
Accepte une fonction qui sera utilisée comme une implémentation de simulation pour un appel à la fonction simulée. Peut être enchaîné de sorte que plusieurs appels de fonction produisent des résultats différents.
- JavaScript
- TypeScript
const mockFn = jest
.fn()
.mockImplementationOnce(cb => cb(null, true))
.mockImplementationOnce(cb => cb(null, false));
mockFn((err, val) => console.log(val)); // true
mockFn((err, val) => console.log(val)); // false
import {jest} from '@jest/globals';
const mockFn = jest
.fn<(cb: (a: null, b: boolean) => void) => void>()
.mockImplementationOnce(cb => cb(null, true))
.mockImplementationOnce(cb => cb(null, false));
mockFn((err, val) => console.log(val)); // true
mockFn((err, val) => console.log(val)); // false
Lorsque la fonction simulée manque d'implémentations définies avec .mockImplementationOnce()
, elle exécutera l'implémentation par défaut définie avec jest.fn(() => defaultValue)
ou .mockImplementation(() => defaultValue)
s'ils ont été appelés :
const mockFn = jest
.fn(() => 'par défaut')
.mockImplementationOnce(() => 'premier appel')
.mockImplementationOnce(() => 'second appel');
mockFn(); // 'premier appel'
mockFn(); // 'second appel'
mockFn(); // 'par défaut'
mockFn(); // 'par défaut'
mockFn.mockName(name)
Accepte une chaîne à utiliser dans le résultat du test à la place de 'jest.fn()'
pour indiquer quelle fonction simulée est référencée.
Par exemple :
const mockFn = jest.fn().mockName('mockedFunction');
// mockFn();
expect(mockFn).toHaveBeenCalled();
Le résultat est cette erreur :
expect(mockedFunction).toHaveBeenCalled()
Expected number of calls: >= 1
Received number of calls: 0
mockFn.mockReturnThis()
Shorthand for:
jest.fn(function () {
return this;
});
mockFn.mockReturnValue(value)
Shorthand for:
jest.fn().mockImplementation(() => value);
Accepte une valeur qui sera retournée chaque fois que la fonction simulée est appelée.
- JavaScript
- TypeScript
const mock = jest.fn();
mock.mockReturnValue(42);
mock(); // 42
mock.mockReturnValue(43);
mock(); // 43
import {jest} from '@jest/globals';
const mock = jest.fn<() => number>();
mock.mockReturnValue(42);
mock(); // 42
mock.mockReturnValue(43);
mock(); // 43
mockFn.mockReturnValueOnce(value)
Shorthand for:
jest.fn().mockImplementationOnce(() => value);
Accepte une valeur qui sera retournée pour un appel à la fonction simulée. Peut être enchaîné de sorte que les appels successifs à la fonction simulée retournent des valeurs différentes. Quand il n'y a plus de valeurs mockReturnValueOnce
à utiliser, les appels retourneront une valeur spécifiée par mockReturnValue
.
- JavaScript
- TypeScript
const mockFn = jest
.fn()
.mockReturnValue('par défaut')
.mockReturnValueOnce('premier appel')
.mockReturnValueOnce('deuxième appel');
mockFn(); // 'premier appel'
mockFn(); // 'deuxième appel'
mockFn(); // 'par défaut'
mockFn(); // 'par défaut'
import {jest} from '@jest/globals';
const mockFn = jest
.fn<() => string>()
.mockReturnValue('default')
.mockReturnValueOnce('first call')
.mockReturnValueOnce('second call');
mockFn(); // 'first call'
mockFn(); // 'second call'
mockFn(); // 'default'
mockFn(); // 'default'
mockFn.mockResolvedValue(value)
Shorthand for:
jest.fn().mockImplementation(() => Promise.resolve(value));
Utile pour simuler les fonctions asynchrones dans les tests asynchrones :
- JavaScript
- TypeScript
test('async test', async () => {
const asyncMock = jest.fn().mockResolvedValue(43);
await asyncMock(); // 43
});
import {jest, test} from '@jest/globals';
test('async test', async () => {
const asyncMock = jest.fn<() => Promise<number>>().mockResolvedValue(43);
await asyncMock(); // 43
});
mockFn.mockResolvedValueOnce(value)
Shorthand for:
jest.fn().mockImplementationOnce(() => Promise.resolve(value));
Utile pour résoudre des valeurs différentes sur plusieurs appels asynchrones :
- JavaScript
- TypeScript
test('async test', async () => {
const asyncMock = jest
.fn()
.mockResolvedValue('par défaut')
.mockResolvedValueOnce('premier appel')
.mockResolvedValueOnce('deuxième appel');
await asyncMock(); // 'premier appel'
await asyncMock(); // 'deuxième appel'
await asyncMock(); // 'par défaut'
await asyncMock(); // 'par défaut'
});
import {jest, test} from '@jest/globals';
test('async test', async () => {
const asyncMock = jest
.fn<() => Promise<string>>()
.mockResolvedValue('default')
.mockResolvedValueOnce('first call')
.mockResolvedValueOnce('second call');
await asyncMock(); // 'first call'
await asyncMock(); // 'second call'
await asyncMock(); // 'default'
await asyncMock(); // 'default'
});
mockFn.mockRejectedValue(value)
Shorthand for:
jest.fn().mockImplementation(() => Promise.reject(value));
Utile pour créer des fonctions simulées asynchrones qui seront toujours rejetées :
- JavaScript
- TypeScript
test('async test', async () => {
const asyncMock = jest
.fn()
.mockRejectedValue(new Error('Async error message'));
await asyncMock(); // lève 'Async error message'
});
import {jest, test} from '@jest/globals';
test('async test', async () => {
const asyncMock = jest
.fn<() => Promise<never>>()
.mockRejectedValue(new Error('Async error message'));
await asyncMock(); // throws 'Async error message'
});
mockFn.mockRejectedValueOnce(value)
Shorthand for:
jest.fn().mockImplementationOnce(() => Promise.reject(value));
Utile avec .mockResolvedValueOnce()
ou pour rejeter avec des exceptions différentes sur plusieurs appels asynchrones :
- JavaScript
- TypeScript
test('async test', async () => {
const asyncMock = jest
.fn()
.mockResolvedValueOnce('premier appel')
.mockRejectedValueOnce(new Error('Async error message'));
await asyncMock(); // 'premier appel'
await asyncMock(); // lève 'Async error message'
});
import {jest, test} from '@jest/globals';
test('async test', async () => {
const asyncMock = jest
.fn<() => Promise<string>>()
.mockResolvedValueOnce('first call')
.mockRejectedValueOnce(new Error('Async error message'));
await asyncMock(); // 'first call'
await asyncMock(); // throws 'Async error message'
});
TypeScript Usage
Veuillez consulter le guide Premiers pas pour plus de détails sur la façon de configurer Jest avec TypeScript.
jest.fn(implementation?)
Les typages simulés corrects seront déduits, si l'implémentation est passée à la fonction jest.fn()
. Il existe de nombreux cas d'utilisation où l'implémentation est omise. Pour assurer la sécurité des types, vous pouvez passer un argument de type générique (voir aussi les exemples ci-dessus pour plus de référence) :
import {expect, jest, test} from '@jest/globals';
import type add from './add';
import calculate from './calc';
test('calculate appelle add', () => {
// Crée une nouvelle simulation qui peut être utilisé à la place de `add`.
const mockAdd = jest.fn<typeof add>();
// `.mockImplementation()` peut maintenant déduire que `a` et `b` sont des `number`
// et que la valeur renvoyée est un `number`.
mockAdd.mockImplementation((a, b) => {
// Oui, cette fonction simulée ajoute toujours deux nombres mais imaginez que
// c'est une fonction complexe que nous simulons.
return a + b
});
// `mockAdd` est correctement typé et donc accepté par tout
// ce que requiert `add`.
calculate(mockAdd, 1, 2);
expect(mockAdd).toHaveBeenCalledTimes(1);
expect(mockAdd).toHaveBeenCalledWith(1, 2);
});