Vai al contenuto principale
{ "message": "Versione: Prossima", "description": "" }

Mock Manuali

Traduzione Beta Non Ufficiale

Questa pagina è stata tradotta da PageTurner AI (beta). Non ufficialmente approvata dal progetto. Hai trovato un errore? Segnala problema →

I mock manuali vengono utilizzati per sostituire funzionalità con dati fittizi. Ad esempio, invece di accedere a risorse remote come siti web o database, potresti creare un mock manuale che utilizza dati falsi. Ciò garantisce test veloci e non instabili.

Mock di moduli utente

I mock manuali si definiscono creando un modulo in una sottodirectory __mocks__/ adiacente al modulo originale. Per esempio, per mockare un modulo user nella directory models, crea un file user.js nella directory models/__mocks__.

{ "message": "attenzione", "description": "The default label used for the Caution admonition (:::caution)" }

La cartella __mocks__ è case-sensitive: nominarla __MOCKS__ causerà errori su alcuni sistemi.

nota

Quando richiediamo il modulo nei test (per usare il mock manuale invece dell'implementazione reale), è necessario chiamare esplicitamente jest.mock('./moduleName').

Mock di moduli Node

Se il modulo da mockare è un modulo Node (es. lodash), il mock va posizionato nella directory __mocks__ adiacente a node_modules (a meno che roots non punti a un'altra cartella) e verrà mockato automaticamente. Non serve chiamare esplicitamente jest.mock('module_name').

I moduli con scope (scoped packages) si mockano creando un file in una struttura di directory che corrisponda al nome del modulo. Per esempio, per mockare @scope/project-name, crea un file in __mocks__/@scope/project-name.js, creando di conseguenza la directory @scope/.

{ "message": "attenzione", "description": "The default label used for the Caution admonition (:::caution)" }

Per mockare i moduli integrati di Node (es. fs o path), è necessario chiamare esplicitamente jest.mock('path') perché questi moduli non vengono mockati di default.

Esempi

.
├── config
├── __mocks__
│   └── fs.js
├── models
│   ├── __mocks__
│   │   └── user.js
│   └── user.js
├── node_modules
└── views

Quando esiste un mock manuale per un modulo, Jest lo utilizzerà quando viene chiamato jest.mock('moduleName'). Con automock impostato su true, verrà usato il mock manuale invece di quello automatico, anche senza chiamare jest.mock('moduleName'). Per disabilitare questo comportamento, chiama jest.unmock('moduleName') nei test che devono usare l'implementazione reale.

info

Per un mocking corretto, jest.mock('moduleName') deve trovarsi nello stesso scope dell'istruzione require/import.

Ecco un esempio simulato: un modulo che fornisce il riepilogo dei file in una directory, usando il modulo integrato fs.

FileSummarizer.js
'use strict';

const fs = require('fs');

function summarizeFilesInDirectorySync(directory) {
return fs.readdirSync(directory).map(fileName => ({
directory,
fileName,
}));
}

exports.summarizeFilesInDirectorySync = summarizeFilesInDirectorySync;

Per evitare l'accesso al disco (lento e instabile), creiamo un mock manuale per fs estendendo un mock automatico. Il nostro mock implementerà versioni personalizzate delle API fs:

__mocks__/fs.js
'use strict';

const path = require('path');

const fs = jest.createMockFromModule('fs');

// This is a custom function that our tests can use during setup to specify
// what the files on the "mock" filesystem should look like when any of the
// `fs` APIs are used.
let mockFiles = Object.create(null);
function __setMockFiles(newMockFiles) {
mockFiles = Object.create(null);
for (const file in newMockFiles) {
const dir = path.dirname(file);

if (!mockFiles[dir]) {
mockFiles[dir] = [];
}
mockFiles[dir].push(path.basename(file));
}
}

// A custom version of `readdirSync` that reads from the special mocked out
// file list set via __setMockFiles
function readdirSync(directoryPath) {
return mockFiles[directoryPath] || [];
}

fs.__setMockFiles = __setMockFiles;
fs.readdirSync = readdirSync;

module.exports = fs;

Ora scriviamo il test. In questo caso jest.mock('fs') deve essere chiamato esplicitamente perché fs è un modulo integrato di Node:

__tests__/FileSummarizer-test.js
'use strict';

jest.mock('fs');

describe('listFilesInDirectorySync', () => {
const MOCK_FILE_INFO = {
'/path/to/file1.js': 'console.log("file1 contents");',
'/path/to/file2.txt': 'file2 contents',
};

beforeEach(() => {
// Set up some mocked out file info before each test
require('fs').__setMockFiles(MOCK_FILE_INFO);
});

test('includes all files in the directory in the summary', () => {
const FileSummarizer = require('../FileSummarizer');
const fileSummary =
FileSummarizer.summarizeFilesInDirectorySync('/path/to');

expect(fileSummary.length).toBe(2);
});
});

L'esempio usa jest.createMockFromModule per generare un mock automatico e sovrascriverne il comportamento. Questo approccio è consigliato ma opzionale. Se preferisci non usare il mock automatico, puoi esportare funzioni personalizzate dal file di mock. Gli svantaggi dei mock completamente manuali sono la manutenzione: vanno aggiornati manualmente a ogni modifica del modulo originale. Per questo è preferibile usare o estendere il mock automatico quando possibile.

Per garantire che un mock manuale e la sua implementazione reale rimangano sincronizzati, può essere utile importare il modulo reale usando jest.requireActual(moduleName) nel tuo mock manuale e integrarlo con funzioni mock prima di esportarlo.

Il codice per questo esempio è disponibile su examples/manual-mocks.

Utilizzo con import di moduli ES

Se utilizzi import di moduli ES, normalmente tenderai a inserire le tue istruzioni import all'inizio del file di test. Tuttavia spesso è necessario istruire Jest a usare un mock prima che i moduli lo utilizzino. Per questo motivo, Jest solleverà automaticamente le chiamate jest.mock all'inizio del modulo (prima di qualsiasi import). Per saperne di più e vedere questa funzionalità in azione, consulta questo repository.

{ "message": "attenzione", "description": "The default label used for the Caution admonition (:::caution)" }

Le chiamate jest.mock non possono essere sollevate all'inizio del modulo se hai abilitato il supporto per i moduli ECMAScript. Il caricatore di moduli ESM valuta sempre gli import statici prima di eseguire il codice. Vedi ECMAScriptModules per i dettagli.

Mocking di metodi non implementati in JSDOM

Se del codice utilizza un metodo non ancora implementato in JSDOM (l'implementazione DOM usata da Jest), testarlo risulta complesso. È il caso ad esempio di window.matchMedia(). Jest restituirà TypeError: window.matchMedia is not a function e non eseguirà correttamente il test.

In questi casi, simulare matchMedia nel file di test dovrebbe risolvere il problema:

Object.defineProperty(window, 'matchMedia', {
writable: true,
value: jest.fn().mockImplementation(query => ({
matches: false,
media: query,
onchange: null,
addListener: jest.fn(), // deprecated
removeListener: jest.fn(), // deprecated
addEventListener: jest.fn(),
removeEventListener: jest.fn(),
dispatchEvent: jest.fn(),
})),
});

Questo approccio funziona se window.matchMedia() viene utilizzato in una funzione (o metodo) richiamata durante il test. Se window.matchMedia() viene eseguito direttamente nel file testato, Jest segnalerà lo stesso errore. In questo caso, la soluzione consiste nello spostare il mock manuale in un file separato e includerlo nel test prima del file testato:

import './matchMedia.mock'; // Must be imported before the tested file
import {myMethod} from './file-to-test';

describe('myMethod()', () => {
// Test the method here...
});