Skip to content
Vitest 1
Main Navigation ÚtmutatóAPIKonfigurációHaladó
1.6.1
0.34.6

magyar

English
简体中文
繁體中文
Español
Français
Русский
Português – Brasil
Deutsch
日本語
한국어
Italiano
Polski
Türkçe
čeština

magyar

English
简体中文
繁體中文
Español
Français
Русский
Português – Brasil
Deutsch
日本語
한국어
Italiano
Polski
Türkçe
čeština

Megjelenés

Sidebar Navigation

Útmutató

Miért a Vitest?

Első lépések

Funkciók

Munkaterület

Parancssori felület

Tesztszűrés

Reporterek

Lefedettség

Pillanatképek

Mockolás

Típusok tesztelése

Vitest UI

Böngésző mód

Forráskódba épített tesztelés

Tesztkörnyezet

Tesztkörnyezet

Egyezésvizsgálók kiterjesztése

IDE integrációk

Hibakeresés

Összehasonlítás más tesztfuttatókkal

Migrálási útmutató

Gyakori hibák

A teljesítmény javítása

API

Teszt API Dokumentáció

Mock függvények

Vi

expect

expectTypeOf

assert

assertType

Konfiguráció

A Vitest konfigurációs fájl beállítása

Vitest konfigurálása

Ezen az oldalon

Mockolás ​

Tesztek írásakor előbb-utóbb szükségessé válik belső vagy külső szolgáltatások "hamis" verziójának létrehozása. Ezt általában mockolásnak nevezzük. A Vitest segédfüggvényeket biztosít a vi segítővel. Importálhatod a import { vi } from 'vitest' használatával, vagy globálisan is elérheted (ha a globális konfiguráció engedélyezve van).

WARNING

A mockok állapotváltozásainak elkerülése érdekében ne felejtsd el törölni vagy visszaállítani a mockokat minden tesztfuttatás előtt vagy után! További információért lásd a mockReset dokumentációt.

Ha azonnal belevágnál, nézd meg az [API szekciót]; ha nem, olvass tovább, hogy mélyebben belemerülj a mockolás világába.

Dátumok ​

Néha szükség lehet a dátum kontrollálására, hogy biztosítsd a konzisztenciát a tesztelés során. A Vitest a @sinonjs/fake-timers csomagot használja az időzítők, valamint a rendszerdátum manipulálására. Az API-ról részletesebben itt találsz információt.

Példa ​

js
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(() => {
    // tell vitest we use mocked time
    vi.useFakeTimers();
  });

  afterEach(() => {
    // restoring date after each test run
    vi.useRealTimers();
  });

  it('allows purchases within business hours', () => {
    // set hour within business hours
    const date = new Date(2000, 1, 1, 13);
    vi.setSystemTime(date);

    // access Date.now() will result in the date set above
    expect(purchase()).toEqual({ message: 'Success' });
  });

  it('disallows purchases outside of business hours', () => {
    // set hour outside business hours
    const date = new Date(2000, 1, 1, 19);
    vi.setSystemTime(date);

    // access Date.now() will result in the date set above
    expect(purchase()).toEqual({ message: 'Error' });
  });
});

Függvények ​

A függvények mockolása két különböző kategóriába sorolható: kémkedés (spying) és mockolás.

Néha csak azt kell ellenőrizned, hogy egy adott függvény meghívásra került-e (és esetleg milyen argumentumokkal). Ezekben az esetekben egy kém (spy) lenne minden, amire szükséged van, amelyet közvetlenül a vi.spyOn() segítségével használhatsz (további információ itt).

A spy-ok azonban csak a függvények megfigyelésében segíthetnek, nem képesek megváltoztatni ezen függvények implementációját. Abban az esetben, ha egy függvény hamis (vagy mockolt) verzióját kell létrehoznunk, használhatjuk a vi.fn()-t (további információ itt).

A Tinyspy-t használjuk a függvények mockolásának alapjaként, de van saját csomagunk, hogy jest kompatibilis legyen. Mind a vi.fn(), mind a vi.spyOn() ugyanazokat a metódusokat osztja meg, azonban csak a vi.fn() visszatérési értéke hívható.

Példa ​

js
import { afterEach, describe, expect, it, vi } from 'vitest';

function getLatest(index = messages.items.length - 1) {
  return messages.items[index];
}

const messages = {
  items: [
    { message: 'Simple test message', from: 'Testman' },
    // ...
  ],
  getLatest, // can also be a `getter or setter if supported`
};

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ábbi információk ​

  • Jest Mock Functions

Globális változók ​

A vi.stubGlobal segítővel mockolhatod azokat a globális változókat, amelyek nincsenek jelen a jsdom-ban vagy a node-ban. Ez a globális változó értékét a globalThis objektumba helyezi.

ts
import { vi } from 'vitest';

const IntersectionObserverMock = vi.fn(() => ({
  disconnect: vi.fn(),
  observe: vi.fn(),
  takeRecords: vi.fn(),
  unobserve: vi.fn(),
}));

vi.stubGlobal('IntersectionObserver', IntersectionObserverMock);

// now you can access it as `IntersectionObserver` or `window.IntersectionObserver`

Modulok ​

A modulok mockolása lehetővé teszi a harmadik féltől származó könyvtárak használatának megfigyelését, az argumentumok és a kimenet tesztelését, vagy akár az implementáció újradefiniálását.

A részletes API leírásért lásd a vi.mock() API szekciót.

Automockoló algoritmus ​

Ha a kódod egy mockolt modult importál anélkül, hogy tartozna hozzá __mocks__ fájl vagy factory, a Vitest magát a modult fogja mockolni a meghívásával és az összes export mockolásával.

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élyen klónozásra kerül
  • Az osztályok minden példánya és azok prototípusai mélyen klónozásra kerülnek

Virtuális modulok ​

A Vitest támogatja a Vite virtuális moduljainak mockolását. Ez másképp működik, mint a virtuális modulok kezelése a Jestben. Ahelyett, hogy a virtual: true értéket adnánk át egy vi.mock függvénynek, meg kell mondanod a Vite-nak, hogy a modul létezik, különben az elemzés során hiba történik. Ezt többféleképpen teheted meg:

  1. Álnevet adsz meg
ts
// vitest.config.js
export default {
  test: {
    alias: {
      '$app/forms': resolve('./mocks/forms.js'),
    },
  },
};
  1. Bővítményt adsz meg, amely felold egy virtuális modult
ts
// vitest.config.js
export default {
  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 hozhatsz létre különböző virtuális belépési pontokat. Ha több virtuális modult irányítasz át egyetlen fájlba, akkor azokat a vi.mock mind befolyásolja, ezért ügyelj arra, hogy egyedi azonosítókat használj.

A Mockolás Csapdái ​

Vigyázz, hogy nem lehet mockolni olyan metódusok hívásait, amelyek ugyanazon fájlban más metódusokból hívódnak meg. Például ebben a kódkban:

ts
export function foo() {
  return 'foo';
}

export function foobar() {
  return `${foo()}bar`;
}

Nem lehet mockolni a foo metódust kívülről, mert közvetlenül hivatkoznak rá. Tehát ez a kód nem lesz hatással a foo hívásra a foobar-ban (de hatással lesz a foo hívásra más modulokban):

ts
import { vi } from 'vitest';
import * as mod from './foobar.js';

// ez csak a "foo"-t fogja befolyásolni az eredeti modulon kívül
vi.spyOn(mod, 'foo');
vi.mock('./foobar.js', async importOriginal => {
  return {
    ...(await importOriginal<typeof import('./foobar.js')>()),
    // ez csak a "foo"-t fogja befolyásolni az eredeti modulon kívül
    foo: () => 'mocked',
  };
});

Ezt a viselkedést megerősítheted, ha közvetlenül megadod a foobar metódus implementációját:

ts
// foobar.test.js
import * as mod from './foobar.js';

vi.spyOn(mod, 'foo');

// az exportált foo a mockolt metódusra hivatkozik
mod.foobar(mod.foo);
ts
// foobar.js
export function foo() {
  return 'foo';
}

export function foobar(injectedFoo) {
  return injectedFoo !== foo; // false
}

Ez a szándékos viselkedés. Általában rossz kódra utal, ha a mockolás ilyen módon történik. Fontold meg a kód több fájlra bontását, vagy az alkalmazás architektúrájának javítását olyan technikákkal, mint a függőség injektálása.

Példa ​

js
import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest';
import { Client } from 'pg';
import { failure, success } from './handlers.js';

// handlers
export function success(data) {}
export function failure(data) {}

// get todos
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('teendőlista lekérése', () => {
  let client;

  beforeEach(() => {
    client = new Client();
  });

  afterEach(() => {
    vi.clearAllMocks();
  });

  it('sikeresen vissza kell adnia az elemeket.', 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('hibát kell dobnia.', 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 });
  });
});

Kérések ​

Mivel a Vitest Node-ban fut, a hálózati kérések mockolása nehézkes; a webes API-k nem érhetők el, 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. Ez lehetővé teszi mind a REST, mind a 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 végrehajtott kéréseket, lehetővé téve a használatát anélkül, hogy meg kellene változtatnod az alkalmazáskódodat. Böngészőben ez a Service Worker API-t használja. A Node.js-ben és a Vitest esetében a @mswjs/interceptors-t használja. Ha többet szeretnél megtudni az MSW-ről, olvasd el a bevezetőjüket.

Konfiguráció ​

Az alábbiak szerint használhatod a setup fájlban:

js
import { afterAll, afterEach, beforeAll } from 'vitest';
import { setupServer } from 'msw/node';
import { HttpResponse, graphql, http } 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 graphqlHandlers = [
  graphql.query('ListPosts', () => {
    return HttpResponse.json({
      data: { posts },
    });
  }),
];

const server = setupServer(...restHandlers, ...graphqlHandlers);

// Start server before all tests
beforeAll(() => server.listen({ onUnhandledRequest: 'error' }));

//  Close server after all tests
afterAll(() => server.close());

// Reset handlers after each test `important for test isolation`
afterEach(() => server.resetHandlers());

A szerver onUnhandleRequest: 'error' beállítással történő konfigurálása biztosítja, hogy hiba keletkezzen, ha olyan kérés érkezik, amelyhez nincs definiálva kéréskezelő.

Példa ​

Van egy teljes működő példánk, amely MSW-t használ: React Testing with MSW.

További információk ​

Az MSW sokkal többet tud. Hozzáférhetsz a cookie-khoz és a lekérdezési paraméterekhez, definiálhatsz mock hiba válaszokat és még sok mást! Ha mindent meg szeretnél tudni, amit az MSW-vel tehetsz, olvasd el a dokumentációjukat.

Időzítők ​

Amikor időzítéseket vagy intervallumokat használó kódot tesztelünk, ahelyett, hogy a tesztek várakoznának vagy időtúllépést okoznának, felgyorsíthatjuk a tesztelést a setTimeout és a setInterval hívásokat mockoló "hamis" időzítőkkel.

A részletesebb API leíráshoz lásd a vi.useFakeTimers API szekciót.

Példa ​

js
import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest';

function executeAfterTwoHours(func) {
  setTimeout(func, 1000 * 60 * 60 * 2); // 2 hours
}

function executeEveryMinute(func) {
  setInterval(func, 1000 * 60); // 1 minute
}

const mock = vi.fn(() => console.log('executed'));

describe('késleltetett végrehajtás.', () => {
  beforeEach(() => {
    vi.useFakeTimers();
  });
  afterEach(() => {
    vi.restoreAllMocks();
  });
  it('végre kell hajtania a függvényt.', () => {
    executeAfterTwoHours(mock);
    vi.runAllTimers();
    expect(mock).toHaveBeenCalledTimes(1);
  });
  it('nem szabad végrehajtania a függvényt.', () => {
    executeAfterTwoHours(mock);
    // advancing by 2ms won't trigger the func
    vi.advanceTimersByTime(2);
    expect(mock).not.toHaveBeenCalled();
  });
  it('percenként végre kell hajtania.', () => {
    executeEveryMinute(mock);
    vi.advanceTimersToNextTimer();
    expect(mock).toHaveBeenCalledTimes(1);
    vi.advanceTimersToNextTimer();
    expect(mock).toHaveBeenCalledTimes(2);
  });
});

Segédlet ​

INFO

Az alábbi példákban a vi közvetlenül a vitest-ből van importálva. Használhatod globálisan is, ha a konfigurációban a globals értékét true-ra állítod.

A következőt szeretném…

A method metódus kémlelése ​

ts
const instance = new SomeClass();
vi.spyOn(instance, 'method');

Exportált változók mockolása ​

js
// some-path.js
export const getter = 'variable';
ts
// some-path.test.ts
import * as exports from './some-path.js';

vi.spyOn(exports, 'getter', 'get').mockReturnValue('mocked');

Exportált függvény mockolása ​

  1. Példa vi.mock használatával:

WARNING

Ne feledje, hogy a vi.mock hívás feljebb kerül a fájl tetejére. Mindig az összes importálás előtt végrehajtásra kerül.

ts
// ./some-path.js
export function method() {}
ts
import { method } from './some-path.js';

vi.mock('./some-path.js', () => ({
  method: vi.fn(),
}));
  1. Példa vi.spyOn használatával:
ts
import * as exports from './some-path.js';

vi.spyOn(exports, 'method').mockImplementation(() => {});

Exportált osztály implementációjának mockolása ​

  1. Példa vi.mock-kal és .prototype-tal:
ts
// some-path.ts
export class SomeClass {}
ts
import { SomeClass } from './some-path.js';

vi.mock('./some-path.js', () => {
  const SomeClass = vi.fn();
  SomeClass.prototype.someMethod = vi.fn();
  return { SomeClass };
});
// A SomeClass.mock.instances tartalmazni fogja a SomeClass példányait
  1. Példa vi.mock és visszatérési érték használatával:
ts
import { SomeClass } from './some-path.js';

vi.mock('./some-path.js', () => {
  const SomeClass = vi.fn(() => ({
    someMethod: vi.fn(),
  }));
  return { SomeClass };
});
// A SomeClass.mock.results tartalmazni fogja a visszaadott objektumokat
  1. Példa vi.spyOn használatával:
ts
import * as exports from './some-path.js';

vi.spyOn(exports, 'SomeClass').mockImplementation(() => {
  // bármi, ami az első két példában szerepel
});

Egy függvény által visszaadott objektum kémlelése ​

  1. Példa gyorsítótár (cache) használatával:
ts
// some-path.ts
export function useObject() {
  return { method: () => true };
}
ts
// useObject.js
import { useObject } from './some-path.js';

const obj = useObject();
obj.method();
ts
// useObject.test.js
import { useObject } from './some-path.js';

vi.mock('./some-path.js', () => {
  let _cache;
  const useObject = () => {
    if (!_cache) {
      _cache = {
        method: vi.fn(),
      };
    }
    // a useObject() minden hívásakor
    // ugyanazt az objektum referenciát adja vissza
    return _cache;
  };
  return { useObject };
});

const obj = useObject();
// az `obj.method` meghívásra került a `some-path` modulban
expect(obj.method).toHaveBeenCalled();

Egy modul egy részének mockolása ​

ts
import { mocked, original } from './some-path.js';

vi.mock('./some-path.js', async importOriginal => {
  const mod = await importOriginal<typeof import('./some-path.js')>();
  return {
    ...mod,
    mocked: vi.fn(),
  };
});
original(); // eredeti viselkedés
mocked(); // egy kémlelő függvény

Az aktuális dátum mockolása ​

A Date időpontjának mockolásához használhatod a vi.setSystemTime segédfüggvényt. Ez az érték nem fog automatikusan visszaállni a különböző tesztek között.

Ne feledd, hogy a vi.useFakeTimers használata szintén megváltoztatja a Date időpontját.

ts
const mockDate = new Date(2022, 0, 1);
vi.setSystemTime(mockDate);
const now = new Date();
expect(now.valueOf()).toBe(mockDate.valueOf());
// a mockolt idő visszaállítása
vi.useRealTimers();

Globális változó mockolása ​

Globális változót beállíthatsz érték hozzárendelésével a globalThis-hez, vagy a vi.stubGlobal segédfüggvény használatával. A vi.stubGlobal használatakor ez nem fog automatikusan visszaállni a különböző tesztek között, hacsak nem engedélyezed az unstubGlobals konfigurációs opciót, vagy nem hívod meg a vi.unstubAllGlobals függvényt.

ts
vi.stubGlobal('__VERSION__', '1.0.0');
expect(__VERSION__).toBe('1.0.0');

Az import.meta.env mockolása ​

  1. A környezeti változó megváltoztatásához egyszerűen hozzárendelhet egy új értéket.

WARNING

A környezeti változó értéke nem fog automatikusan visszaállni a különböző tesztek között.

ts
import { beforeEach, expect, it } from 'vitest';

// manuálisan visszaállíthatod a `beforeEach` hook-ban
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');
});
  1. Ha automatikusan szeretné visszaállítani az értékeket, használhatja a vi.stubEnv segédfüggvényt az engedélyezett unstubEnvs konfigurációs opcióval (vagy manuálisan hívhatja a vi.unstubAllEnvs](/api/vi#vi-unstuballenvs) függvényt egy beforeEach hook-ban):
ts
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ásra kerül egy másik teszt futtatása előtt', () => {
  expect(import.meta.env.VITE_ENV).toBe('test');
});
ts
// vitest.config.ts
export default {
  test: {
    unstubAllEnvs: true,
  },
};
Pager
Előző oldalPillanatképek
Következő oldalTípusok tesztelése

A MIT licenc alapján kiadva.

Copyright (c) 2024 Mithril Contributors

https://v1.vitest.dev/guide/mocking

A MIT licenc alapján kiadva.

Copyright (c) 2024 Mithril Contributors