Mockolás
Tesztíráskor előbb-utóbb szükségessé válik egy belső vagy külső szolgáltatás „ál” verziójának létrehozása. Ezt általában mockolásnak nevezik. A Vitest a vi
segédfüggvényein keresztül biztosít ehhez eszközöket. Importálhatja a vitest
modulból, vagy globálisan is elérheti, ha a globals
konfiguráció engedélyezve van.
WARNING
Mindig emlékezzen a mockok törlésére vagy visszaállítására minden teszt futtatása előtt vagy után. Ez segít visszavonni a mock állapotváltozásait a futtatások között! További információkért lásd a mockReset
dokumentációját.
Ha nem ismeri a vi.fn
, vi.mock
vagy vi.spyOn
metódusokat, először nézze meg az API szekciót.
Dátumok
Néha szükséges a dátum ellenőrzése a tesztelés során a konzisztencia biztosítása érdekében. A Vitest a @sinonjs/fake-timers
csomagot használja az időzítők és a rendszerdátum manipulálására. Az API-ról részletesebben itt talál információt.
Példa
import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest';
const businessHours = [9, 17];
function purchase() {
const currentHour = new Date().getHours();
const [open, close] = businessHours;
if (currentHour > open && currentHour < close) {
return { message: 'Success' };
}
return { message: 'Error' };
}
describe('purchasing flow', () => {
beforeEach(() => {
// jelezzük a Vitestnek, hogy mockolt időt használunk
vi.useFakeTimers();
});
afterEach(() => {
// dátum visszaállítása minden tesztfutás után
vi.useRealTimers();
});
it('allows purchases within business hours', () => {
// idő beállítása munkaidőn belülre
const date = new Date(2000, 1, 1, 13);
vi.setSystemTime(date);
// a Date.now() a fent beállított időpontot fogja visszaadni
expect(purchase()).toEqual({ message: 'Success' });
});
it('disallows purchases outside of business hours', () => {
// idő beállítása munkaidőn kívülre
const date = new Date(2000, 1, 1, 19);
vi.setSystemTime(date);
// a Date.now() a fent beállított időpontot fogja visszaadni
expect(purchase()).toEqual({ message: 'Error' });
});
});
Függvények
A függvények mockolása két különböző kategóriába sorolható: megfigyelés és mockolás.
Néha csak azt kell ellenőriznie, hogy egy adott függvényt meghívtak-e (és esetleg milyen argumentumokat adtak át). Ezekben az esetekben elegendő egy spy (megfigyelő), amelyet közvetlenül a vi.spyOn()
-nal használhat (további információ itt).
A spy-ok azonban csak a függvények megfigyelésében segíthetnek, nem tudják megváltoztatni ezen függvények implementációját. Abban az esetben, ha egy függvény ál (vagy mockolt) verzióját kell létrehoznunk, használhatjuk a vi.fn()
-t (további információ itt).
A Tinyspy alapjait használjuk a függvények mockolásához, de van saját burkolónk, hogy jest
kompatibilissé tegyük. Mind a vi.fn()
, mind a vi.spyOn()
ugyanazokat a metódusokat használja, azonban csak a vi.fn()
által visszaadott érték hívható meg.
Példa
import { afterEach, describe, expect, it, vi } from 'vitest';
const messages = {
items: [
{ message: 'Simple test message', from: 'Testman' },
// ...
],
getLatest, // lehet `getter` vagy `setter` is (amennyiben támogatott)
};
function getLatest(index = messages.items.length - 1) {
return messages.items[index];
}
describe('reading messages', () => {
afterEach(() => {
vi.restoreAllMocks();
});
it('should get the latest message with a spy', () => {
const spy = vi.spyOn(messages, 'getLatest');
expect(spy.getMockName()).toEqual('getLatest');
expect(messages.getLatest()).toEqual(
messages.items[messages.items.length - 1]
);
expect(spy).toHaveBeenCalledTimes(1);
spy.mockImplementationOnce(() => 'access-restricted');
expect(messages.getLatest()).toEqual('access-restricted');
expect(spy).toHaveBeenCalledTimes(2);
});
it('should get with a mock', () => {
const mock = vi.fn().mockImplementation(getLatest);
expect(mock()).toEqual(messages.items[messages.items.length - 1]);
expect(mock).toHaveBeenCalledTimes(1);
mock.mockImplementationOnce(() => 'access-restricted');
expect(mock()).toEqual('access-restricted');
expect(mock).toHaveBeenCalledTimes(2);
expect(mock()).toEqual(messages.items[messages.items.length - 1]);
expect(mock).toHaveBeenCalledTimes(3);
});
});
Továbbiak
Globális változók
Globális változókat, amelyek nincsenek jelen a jsdom
vagy node
környezetben, a vi.stubGlobal
segítővel mockolhatja. Ez a globális változó értékét a globalThis
objektumba illeszti.
import { vi } from 'vitest';
const IntersectionObserverMock = vi.fn(() => ({
disconnect: vi.fn(),
observe: vi.fn(),
takeRecords: vi.fn(),
unobserve: vi.fn(),
}));
vi.stubGlobal('IntersectionObserver', IntersectionObserverMock);
// most már elérheti `IntersectionObserver` vagy `window.IntersectionObserver` néven
Modulok
A mock modulok harmadik féltől származó könyvtárakat kezelnek/fognak el, amelyeket más kódban hívnak meg, lehetővé téve az argumentumok, kimenet tesztelését, vagy akár az implementáció újradeklarálását.
A vi.mock()
API szekciót lásd a részletesebb API leírásért.
Automatikus Mockolási Algoritmus
Ha a kódja egy mockolt modult importál, anélkül, hogy ehhez a modulhoz __mocks__
fájl vagy factory
tartozna, a Vitest magát a modult fogja mockolni, meghívva azt és minden exportot mockolva.
A következő elvek érvényesek:
- Minden tömb kiürítésre kerül.
- Minden primitív és gyűjtemény változatlan marad.
- Minden objektum mélymásolásra kerül.
- Az osztályok és prototípusaik minden példánya mélymásolásra kerül.
Virtuális Modulok
A Vitest támogatja a Vite virtuális modulok mockolását. Ez eltér attól, ahogyan a Jest a virtuális modulokat kezeli. Ahelyett, hogy virtual: true
értéket adna át egy vi.mock
függvénynek, meg kell mondania a Vite-nek, hogy a modul létezik, különben a feldolgozás során hiba lép fel. Ezt többféleképpen teheti meg:
- Adjon meg egy aliast
import { defineConfig } from 'vitest/config';
import { resolve } from 'node:path';
export default defineConfig({
test: {
alias: {
'$app/forms': resolve('./mocks/forms.js'),
},
},
});
- Adjon meg egy plugint, amely feloldja a virtuális modult
import { defineConfig } from 'vitest/config';
export default defineConfig({
plugins: [
{
name: 'virtual-modules',
resolveId(id) {
if (id === '$app/forms') {
return 'virtual:$app/forms';
}
},
},
],
});
A második megközelítés előnye, hogy dinamikusan hozhat létre különböző virtuális belépési pontokat. Ha több virtuális modult egyetlen fájlba irányít át, akkor mindegyiket érinti a vi.mock
, ezért ügyeljen az egyedi azonosítók használatára.
Mockolási buktatók
Fontos megjegyezni, hogy nem lehetséges mockolni azokat a metódushívásokat, amelyek ugyanazon fájl más metódusaiban vannak meghívva. Például ebben a kódban:
export function foo() {
return 'foo';
}
export function foobar() {
return `${foo()}bar`;
}
Nem lehetséges a foo
metódust kívülről mockolni, mert közvetlenül hivatkoznak rá. Tehát ez a kód nem lesz hatással a foobar
belsejében lévő foo
hívásra (de hatással lesz a foo
hívásra más modulokban):
import { vi } from 'vitest';
import * as mod from './foobar.js';
// ez csak az eredeti modulon kívüli "foo"-t érinti
vi.spyOn(mod, 'foo');
vi.mock('./foobar.js', async importOriginal => {
return {
...(await importOriginal<typeof import('./foobar.js')>()),
// ez csak az eredeti modulon kívüli "foo"-t érinti
foo: () => 'mocked',
};
});
Ezt a viselkedést megerősítheti, ha közvetlenül a foobar
metódusnak adja meg az implementációt:
import * as mod from './foobar.js';
vi.spyOn(mod, 'foo');
// az exportált foo a mockolt metódusra hivatkozik
mod.foobar(mod.foo);
export function foo() {
return 'foo';
}
export function foobar(injectedFoo) {
return injectedFoo === foo; // false
}
Ez a szándékolt viselkedés. Általában rossz kód jele, ha a mockolás ilyen módon történik. Fontolja meg a kód refaktorálását több fájlba, vagy az alkalmazás architektúrájának javítását olyan technikák alkalmazásával, mint a függőséginjektálás.
Példa
import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest';
import { Client } from 'pg';
import { failure, success } from './handlers.js';
// teendők lekérése
export async function getTodos(event, context) {
const client = new Client({
// ...clientOptions
});
await client.connect();
try {
const result = await client.query('SELECT * FROM todos;');
client.end();
return success({
message: `${result.rowCount} item(s) returned`,
data: result.rows,
status: true,
});
} catch (e) {
console.error(e.stack);
client.end();
return failure({ message: e, status: false });
}
}
vi.mock('pg', () => {
const Client = vi.fn();
Client.prototype.connect = vi.fn();
Client.prototype.query = vi.fn();
Client.prototype.end = vi.fn();
return { Client };
});
vi.mock('./handlers.js', () => {
return {
success: vi.fn(),
failure: vi.fn(),
};
});
describe('get a list of todo items', () => {
let client;
beforeEach(() => {
client = new Client();
});
afterEach(() => {
vi.clearAllMocks();
});
it('should return items successfully', async () => {
client.query.mockResolvedValueOnce({ rows: [], rowCount: 0 });
await getTodos();
expect(client.connect).toBeCalledTimes(1);
expect(client.query).toBeCalledWith('SELECT * FROM todos;');
expect(client.end).toBeCalledTimes(1);
expect(success).toBeCalledWith({
message: '0 item(s) returned',
data: [],
status: true,
});
});
it('should throw an error', async () => {
const mError = new Error('Unable to retrieve rows');
client.query.mockRejectedValueOnce(mError);
await getTodos();
expect(client.connect).toBeCalledTimes(1);
expect(client.query).toBeCalledWith('SELECT * FROM todos;');
expect(client.end).toBeCalledTimes(1);
expect(failure).toBeCalledWith({ message: mError, status: false });
});
});
Fájlrendszer
A fájlrendszer mockolása biztosítja, hogy a tesztek ne függjenek a tényleges fájlrendszertől, ezáltal megbízhatóbbá és kiszámíthatóbbá téve azokat. Ez az izoláció segít elkerülni a korábbi tesztek mellékhatásait. Lehetővé teszi olyan hibaállapotok és szélső esetek tesztelését, amelyeket nehéz vagy lehetetlen lenne reprodukálni egy tényleges fájlrendszerrel, például engedélyezési problémák, megtelt lemezhelyzetek vagy olvasási/írási hibák.
A Vitest alapból nem biztosít fájlrendszer mockolási API-t. Használhatja a vi.mock
-ot az fs
modul manuális mockolására, de ez nehezen karbantartható. Ehelyett javasoljuk a memfs
használatát. A memfs
egy memóriában lévő fájlrendszert hoz létre, amely szimulálja a fájlrendszer műveleteket anélkül, hogy a tényleges lemezt érintené. Ez a megközelítés gyors és biztonságos, elkerülve a valós fájlrendszerre gyakorolt esetleges mellékhatásokat.
Példa
Ahhoz, hogy minden fs
hívást automatikusan átirányítson a memfs
-re, létrehozhatja a __mocks__/fs.cjs
és __mocks__/fs/promises.cjs
fájlokat a projekt gyökerében:
// használhatunk `import`-ot is, de akkor
// minden exportot explicit módon definiálni kell
const { fs } = require('memfs');
module.exports = fs;
// használhatunk `import`-ot is, de akkor
// minden exportot explicit módon definiálni kell
const { fs } = require('memfs');
module.exports = fs.promises;
import { readFileSync } from 'node:fs';
export function readHelloWorld(path) {
return readFileSync(path, 'utf-8');
}
import { beforeEach, expect, it, vi } from 'vitest';
import { fs, vol } from 'memfs';
import { readHelloWorld } from './read-hello-world.js';
// jelezzük a Vitestnek, hogy az `fs` mockot a `__mocks__` mappából használja
// ez egy setup fájlban is megtehető, ha az `fs`-t mindig mockolni kell
vi.mock('node:fs');
vi.mock('node:fs/promises');
beforeEach(() => {
// a memóriabeli fs állapotának visszaállítása
vol.reset();
});
it('should return correct text', () => {
const path = '/hello-world.txt';
fs.writeFileSync(path, 'hello world');
const text = readHelloWorld(path);
expect(text).toBe('hello world');
});
it('can return a value multiple times', () => {
// a vol.fromJSON segítségével több fájlt is definiálhat
vol.fromJSON(
{
'./dir1/hw.txt': 'hello dir1',
'./dir2/hw.txt': 'hello dir2',
},
// alapértelmezett cwd
'/tmp'
);
expect(readHelloWorld('/tmp/dir1/hw.txt')).toBe('hello dir1');
expect(readHelloWorld('/tmp/dir2/hw.txt')).toBe('hello dir2');
});
Kérések
Mivel a Vitest Node.js környezetben fut, a hálózati kérések mockolása kihívást jelent; a webes API-k nem állnak rendelkezésre, ezért szükségünk van valamire, ami utánozza a hálózati viselkedést. Ehhez a Mock Service Worker használatát javasoljuk. Lehetővé teszi a http
, WebSocket
és GraphQL
hálózati kérések mockolását, és keretrendszer-független.
A Mock Service Worker (MSW) úgy működik, hogy elfogja a tesztek által küldött kéréseket, lehetővé téve a használatát anélkül, hogy megváltoztatná az alkalmazáskódját. Böngészőben ez a ServiceWorker API -t használja. Node.js-ben és a Vitest esetében az @mswjs/interceptors
könyvtárat használja. Az MSW-ről további információkért olvassa el a bevezetőjüket
Konfiguráció
Az alábbiak szerint használhatja a setup fájljában
import { afterAll, afterEach, beforeAll } from 'vitest';
import { setupServer } from 'msw/node';
import { http, HttpResponse } from 'msw';
const posts = [
{
userId: 1,
id: 1,
title: 'first post title',
body: 'first post body',
},
// ...
];
export const restHandlers = [
http.get('https://rest-endpoint.example/path/to/posts', () => {
return HttpResponse.json(posts);
}),
];
const server = setupServer(...restHandlers);
// Szerver indítása minden teszt előtt
beforeAll(() => server.listen({ onUnhandledRequest: 'error' }));
// Szerver bezárása minden teszt után
afterAll(() => server.close());
// Kezelők visszaállítása minden teszt után a tesztek izolálásához
afterEach(() => server.resetHandlers());
import { afterAll, afterEach, beforeAll } from 'vitest';
import { setupServer } from 'msw/node';
import { graphql, HttpResponse } from 'msw';
const posts = [
{
userId: 1,
id: 1,
title: 'first post title',
body: 'first post body',
},
// ...
];
const graphqlHandlers = [
graphql.query('ListPosts', () => {
return HttpResponse.json({
data: { posts },
});
}),
];
const server = setupServer(...graphqlHandlers);
// Szerver indítása minden teszt előtt
beforeAll(() => server.listen({ onUnhandledRequest: 'error' }));
// Szerver bezárása minden teszt után
afterAll(() => server.close());
// Kezelők visszaállítása minden teszt után a tesztek izolálásához
afterEach(() => server.resetHandlers());
import { afterAll, afterEach, beforeAll } from 'vitest';
import { setupServer } from 'msw/node';
import { ws } from 'msw';
const chat = ws.link('wss://chat.example.com');
const wsHandlers = [
chat.addEventListener('connection', ({ client }) => {
client.addEventListener('message', event => {
console.log('Received message from client:', event.data);
// Visszaküldi az ügyfélnek a kapott üzenetet
client.send(`Server received: ${event.data}`);
});
}),
];
const server = setupServer(...wsHandlers);
// Szerver indítása minden teszt előtt
beforeAll(() => server.listen({ onUnhandledRequest: 'error' }));
// Szerver bezárása minden teszt után
afterAll(() => server.close());
// Kezelők visszaállítása minden teszt után a tesztek izolálásához
afterEach(() => server.resetHandlers());
A szerver
onUnhandledRequest: 'error'
konfigurálása biztosítja, hogy hiba dobódjon, amikor olyan kérés érkezik, amelyhez nincs megfelelő kéréskezelő.
Továbbiak
Az MSW-ről sokkal több is van. Hozzáférhet a sütikhez és a lekérdezési paraméterekhez, definiálhat mock hibaüzeneteket, és még sok mást! Az MSW-vel kapcsolatos összes lehetőséget lásd a dokumentációjukban.
Időzítők
Amikor időtúllépéseket vagy intervallumokat tartalmazó kódot tesztelünk, ahelyett, hogy a tesztjeink kivárnák az időt vagy időtúllépnének, felgyorsíthatjuk a tesztjeinket „ál” időzítők használatával, amelyek mockolják a setTimeout
és setInterval
hívásokat.
A vi.useFakeTimers
API szekciót lásd a részletesebb API leírásért.
Példa
import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest';
function executeAfterTwoHours(func) {
setTimeout(func, 1000 * 60 * 60 * 2); // 2 óra
}
function executeEveryMinute(func) {
setInterval(func, 1000 * 60); // 1 perc
}
const mock = vi.fn(() => console.log('executed'));
describe('delayed execution', () => {
beforeEach(() => {
vi.useFakeTimers();
});
afterEach(() => {
vi.restoreAllMocks();
});
it('should execute the function', () => {
executeAfterTwoHours(mock);
vi.runAllTimers();
expect(mock).toHaveBeenCalledTimes(1);
});
it('should not execute the function', () => {
executeAfterTwoHours(mock);
// 2ms-mal való előrehaladás nem fogja elindítani a függvényt
vi.advanceTimersByTime(2);
expect(mock).not.toHaveBeenCalled();
});
it('should execute every minute', () => {
executeEveryMinute(mock);
vi.advanceTimersToNextTimer();
expect(mock).toHaveBeenCalledTimes(1);
vi.advanceTimersToNextTimer();
expect(mock).toHaveBeenCalledTimes(2);
});
});
Osztályok
Egy egész osztályt mockolhat egyetlen vi.fn
hívással – mivel minden osztály függvény is, ez azonnal használható. Fontos megjegyezni, hogy jelenleg a Vitest nem veszi figyelembe a new
kulcsszót, így a new.target
mindig undefined
a függvény törzsében.
class Dog {
name: string;
constructor(name: string) {
this.name = name;
}
static getType(): string {
return 'animal';
}
greet = (): string => {
return `Hi! My name is ${this.name}!`;
};
speak(): string {
return 'bark!';
}
isHungry() {}
feed() {}
}
Ezt az osztályt újra létrehozhatjuk ES5 függvényekkel:
const Dog = vi.fn(function (name) {
this.name = name;
// mock példánymetódusok a konstruktorban, minden példánynak saját spy-ja lesz
this.greet = vi.fn(() => `Hi! My name is ${this.name}!`);
});
// vegye figyelembe, hogy a statikus metódusok közvetlenül a függvényen vannak mockolva,
// nem az osztály példányán
Dog.getType = vi.fn(() => 'mocked animal');
// mockolja a "speak" és "feed" metódusokat az osztály minden példányán
// minden `new Dog()` példány örökölni fogja és megosztja ezeket a kémeket
Dog.prototype.speak = vi.fn(() => 'loud bark!');
Dog.prototype.feed = vi.fn();
WARNING
Ha a konstruktor függvény nem primitív értéket ad vissza, az az érték lesz az új kifejezés eredménye. Ebben az esetben a [[Prototype]]
kötése nem biztos, hogy megfelelő lesz:
const CorrectDogClass = vi.fn(function (name) {
this.name = name;
});
const IncorrectDogClass = vi.fn(name => ({
name,
}));
const Marti = new CorrectDogClass('Marti');
const Newt = new IncorrectDogClass('Newt');
Marti instanceof CorrectDogClass; // ✅ true
Newt instanceof IncorrectDogClass; // ❌ false!
MIKOR HASZNÁLJUK?
Általánosságban elmondható, hogy egy osztályt így hozna létre újra a modulgyártó függvényben, ha az osztályt egy másik modulból exportálják újra:
import { Dog } from './dog.js';
vi.mock(import('./dog.js'), () => {
const Dog = vi.fn();
Dog.prototype.feed = vi.fn();
// ... egyéb mockok
return { Dog };
});
Ez a módszer arra is használható, hogy egy osztály példányát átadjuk egy olyan függvénynek, amely ugyanazt az interfészt várja el:
function feed(dog: Dog) {
// ...
}
import { expect, test, vi } from 'vitest';
import { feed } from '../src/feed.js';
const Dog = vi.fn();
Dog.prototype.feed = vi.fn();
test('can feed dogs', () => {
const dogMax = new Dog('Max');
feed(dogMax);
expect(dogMax.feed).toHaveBeenCalled();
expect(dogMax.isHungry()).toBe(false);
});
Most, amikor létrehozunk egy új Dog
osztálypéldányt, a speak
metódusa (a feed
és greet
mellett) már mockolva van:
const Cooper = new Dog('Cooper');
Cooper.speak(); // hangos ugatás!
Cooper.greet(); // Szia! A nevem Cooper!
// beépített állításokat használhat a hívás érvényességének ellenőrzésére
expect(Cooper.speak).toHaveBeenCalled();
expect(Cooper.greet).toHaveBeenCalled();
const Max = new Dog('Max');
// a prototípushoz rendelt metódusok megosztottak a példányok között
expect(Max.speak).toHaveBeenCalled();
expect(Max.greet).not.toHaveBeenCalled();
Újra hozzárendelhetjük a visszatérési értéket egy adott példányhoz:
const dog = new Dog('Cooper');
// a "vi.mocked" egy típussegítő, mivel
// a TypeScript nem tudja, hogy a Dog egy mockolt osztály,
// bármely függvényt MockInstance<T> típusba burkol
// anélkül, hogy ellenőrizné, hogy a függvény mock-e
vi.mocked(dog.speak).mockReturnValue('vau vau');
dog.speak(); // vau vau
A tulajdonság mockolásához használhatjuk a vi.spyOn(dog, 'name', 'get')
metódust. Ez lehetővé teszi a spy állítások használatát a mockolt tulajdonságon:
const dog = new Dog('Cooper');
const nameSpy = vi.spyOn(dog, 'name', 'get').mockReturnValue('Max');
expect(dog.name).toBe('Max');
expect(nameSpy).toHaveBeenCalledTimes(1);
TIP
Lekérőket és beállítókat is figyelhet ugyanazzal a metódussal.
Csalólap
INFO
A vi
az alábbi példákban közvetlenül a vitest
modulból van importálva. Globálisan is használhatja, ha a globals
beállítást true
-ra állítja a konfigurációjában.
Szeretném, hogy…
Exportált változók mockolása
export const getter = 'variable';
import * as exports from './example.js';
vi.spyOn(exports, 'getter', 'get').mockReturnValue('mocked');
Exportált függvény mockolása
- Példa
vi.mock
-kal:
WARNING
Ne feledje, hogy a vi.mock
hívás a fájl tetejére kerül. Mindig az összes import előtt fog végrehajtódni.
export function method() {}
import { method } from './example.js';
vi.mock('./example.js', () => ({
method: vi.fn(),
}));
- Példa
vi.spyOn
-nal:
import * as exports from './example.js';
vi.spyOn(exports, 'method').mockImplementation(() => {});
Exportált osztály implementációjának mockolása
- Példa
vi.mock
-kal és.prototype
-pal:
export class SomeClass {}
import { SomeClass } from './example.js';
vi.mock(import('./example.js'), () => {
const SomeClass = vi.fn();
SomeClass.prototype.someMethod = vi.fn();
return { SomeClass };
});
// SomeClass.mock.instances SomeClass példányokat fog tartalmazni
- Példa
vi.spyOn
-nal:
import * as mod from './example.js';
const SomeClass = vi.fn();
SomeClass.prototype.someMethod = vi.fn();
vi.spyOn(mod, 'SomeClass').mockImplementation(SomeClass);
Egy függvényből visszaadott objektum megfigyelése
- Példa gyorsítótár használatával:
export function useObject() {
return { method: () => true };
}
import { useObject } from './example.js';
const obj = useObject();
obj.method();
import { useObject } from './example.js';
vi.mock(import('./example.js'), () => {
let _cache;
const useObject = () => {
if (!_cache) {
_cache = {
method: vi.fn(),
};
}
// mostantól minden alkalommal, amikor a useObject() meghívásra kerül,
// ugyanazt az objektumreferenciát adja vissza
return _cache;
};
return { useObject };
});
const obj = useObject();
// az obj.method a some-path-ban lett meghívva
expect(obj.method).toHaveBeenCalled();
Egy modul részének mockolása
import { mocked, original } from './some-path.js';
vi.mock(import('./some-path.js'), async importOriginal => {
const mod = await importOriginal();
return {
...mod,
mocked: vi.fn(),
};
});
original(); // eredeti viselkedéssel rendelkezik
mocked(); // egy kémként viselkedő függvény
WARNING
Ne feledje, hogy ez csak a külső hozzáférést mockolja. Ebben a példában, ha az original
belsőleg hívja a mocked
-et, akkor mindig a modulban definiált függvényt hívja meg, nem a mock factory-ban.
Az aktuális dátum mockolása
A Date
idejének mockolásához használhatja a vi.setSystemTime
segédfüggvényt. Ez az érték nem áll vissza automatikusan a különböző tesztek között.
Fontos megjegyezni, hogy a vi.useFakeTimers
használata is megváltoztatja a Date
idejét.
const mockDate = new Date(2022, 0, 1);
vi.setSystemTime(mockDate);
const now = new Date();
expect(now.valueOf()).toBe(mockDate.valueOf());
// mockolt idő visszaállítása
vi.useRealTimers();
Globális változó mockolása
Globális változót definiálhat úgy, hogy értéket ad a globalThis
-nek, vagy a vi.stubGlobal
segítőt használja. A vi.stubGlobal
használatakor az érték nem áll vissza automatikusan a különböző tesztek között, hacsak nem engedélyezi az unstubGlobals
konfigurációs opciót, vagy nem hívja meg a vi.unstubAllGlobals
függvényt.
vi.stubGlobal('__VERSION__', '1.0.0');
expect(__VERSION__).toBe('1.0.0');
import.meta.env
mockolása
- A környezeti változó felülírásához egyszerűen rendeljen hozzá egy új értéket.
WARNING
A környezeti változó értéke nem áll vissza automatikusan a különböző tesztek között.
import { beforeEach, expect, it } from 'vitest';
// a tesztek futtatása előtt a "VITE_ENV" értéke "test"
const originalViteEnv = import.meta.env.VITE_ENV;
beforeEach(() => {
import.meta.env.VITE_ENV = originalViteEnv;
});
it('changes value', () => {
import.meta.env.VITE_ENV = 'staging';
expect(import.meta.env.VITE_ENV).toBe('staging');
});
- Ha automatikusan vissza szeretné állítani az érték(ek)et, használhatja a
vi.stubEnv
segítőt azunstubEnvs
konfigurációs opció engedélyezésével (vagy manuálisan hívja meg avi.unstubAllEnvs
függvényt egybeforeEach
hookban):
import { expect, it, vi } from 'vitest';
// a tesztek futtatása előtt a "VITE_ENV" értéke "test"
import.meta.env.VITE_ENV === 'test';
it('changes value', () => {
vi.stubEnv('VITE_ENV', 'staging');
expect(import.meta.env.VITE_ENV).toBe('staging');
});
it('az érték visszaállítódik egy másik teszt futtatása előtt', () => {
expect(import.meta.env.VITE_ENV).toBe('test');
});
export default defineConfig({
test: {
unstubEnvs: true,
},
});