Skip to content
Vitest 0
Main Navigation PrůvodceAPIKonfiguracePokročilý
1.6.1
0.34.6

čeština

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

čeština

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

Vzhled

Sidebar Navigation

Průvodce

Proč Vitest

Začínáme

Funkce

Pracovní prostor

Rozhraní příkazového řádku

Filtrování testů

Pokrytí

Snímky

Mockování

Testování typů

Vitest UI

Režim prohlížeče (experimentální)

Testování ve zdrojovém kódu

Kontext testu

Testovací prostředí

Rozšíření matcherů/porovnávačů

Integrace do IDE

Ladění

Srovnání s jinými testovacími nástroji

Průvodce migrací

Běžné chyby

API

Referenční příručka k Test API

Mockování funkcí

Vi

expect

expectTypeOf

assertType

Konfigurace

Konfigurace Vitest

Na této stránce

Mockování ​

Při psaní testů dříve či později narazíte na potřebu vytvořit "falešnou" verzi interní nebo externí služby. Tomu se obvykle říká mockování. Vitest poskytuje pomocné funkce, které vám s tím pomohou, prostřednictvím svého pomocníka vi. Můžete import { vi } from 'vitest' nebo k němu přistupovat globálně (pokud je globální konfigurace povolena).

WARNING

Nezapomeňte vždy smazat nebo obnovit mocky před nebo po každém spuštění testu, abyste zrušili změny stavu mocků mezi spuštěními! Další informace naleznete v dokumentaci mockReset.

Pokud se chcete rovnou pustit do práce, podívejte se na sekci API. Jinak pokračujte ve čtení a prozkoumejte svět mockování podrobněji.

Datum a čas ​

Někdy potřebujete mít kontrolu nad časem, abyste zajistili konzistenci během testování. Vitest používá balíček @sinonjs/fake-timers pro manipulaci s časovači a systémovým datem. Více informací o konkrétním API naleznete zde.

Příklad ​

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(() => {
    // informujeme Vitest, že používáme mockovaný čas
    vi.useFakeTimers();
  });

  afterEach(() => {
    // obnovení data po každém spuštění testu
    vi.useRealTimers();
  });

  it('allows purchases within business hours', () => {
    // nastavíme hodinu v rámci pracovní doby
    const date = new Date(2000, 1, 1, 13);
    vi.setSystemTime(date);

    // přístup k Date.now() vrátí výše nastavené datum
    expect(purchase()).toEqual({ message: 'Success' });
  });

  it('disallows purchases outside of business hours', () => {
    // nastavíme hodinu mimo pracovní dobu
    const date = new Date(2000, 1, 1, 19);
    vi.setSystemTime(date);

    // přístup k Date.now() vrátí výše nastavené datum
    expect(purchase()).toEqual({ message: 'Error' });
  });
});

Funkce ​

Mockování funkcí lze rozdělit do dvou kategorií: spying & mocking (sledování a napodobování).

Někdy potřebujete pouze ověřit, zda byla konkrétní funkce volána (a případně s jakými argumenty). V těchto případech by nám stačilo špehování, které můžete použít přímo s vi.spyOn() (více informací zde).

Špehovací funkce vám umožňují pouze sledovat chování funkcí, nikoli měnit jejich implementaci. V případě, že potřebujeme vytvořit falešnou verzi funkce (nebo mockovanou), můžeme použít vi.fn() (více informací zde).

Používáme Tinyspy jako základ pro mockování funkcí, ale máme vlastní obal, aby byl kompatibilní s jest. Jak vi.fn(), tak vi.spyOn() sdílejí stejné metody, nicméně pouze návratová hodnota vi.fn() je volatelná.

Příklad ​

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);
  });
});

Více ​

  • Jest's Mock Functions

Globální objekty ​

Globální proměnné, které nejsou přítomny v jsdom nebo node, můžete mockovat pomocí pomocníka vi.stubGlobal. Vloží hodnotu globální proměnné do objektu globalThis.

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);

// nyní k němu můžete přistupovat jako `IntersectionObserver` nebo `window.IntersectionObserver`

Moduly ​

Mockování modulů umožňuje sledovat chování knihoven třetích stran volaných ve vašem kódu, testovat jejich argumenty a výstupy a dokonce i měnit jejich implementaci.

Podrobnější popis API naleznete v sekci vi.mock() api.

Automatické mockování ​

Pokud váš kód importuje mockovaný modul bez jakéhokoli přidruženého souboru __mocks__ nebo factory pro tento modul, Vitest bude mockovat samotný modul jeho vyvoláním a mockováním každého exportu.

Platí následující zásady:

  • Všechna pole budou prázdná
  • Všechny primitivy a kolekce zůstanou stejné
  • Všechny objekty budou hluboce klonovány
  • Všechny instance tříd a jejich prototypy budou hluboce klonovány

Příklad ​

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

// Obslužné funkce
export function success(data) {}
export function failure(data) {}

// Získání úkolů
export async function getTodos(event, context) {
  const client = new Client({
    // ...možnosti klienta
  });

  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 });
  });
});

Požadavky ​

Protože Vitest běží v Node.js, mockování síťových požadavků je složité; webová API nejsou k dispozici, takže potřebujeme něco, co bude napodobovat chování sítě. Doporučujeme Mock Service Worker k dosažení tohoto cíle. Umožní vám mockovat síťové požadavky REST i GraphQL a je nezávislý na frameworku.

Mock Service Worker (MSW) funguje tak, že zachycuje požadavky, které vaše testy provádějí, což vám umožňuje jej používat bez změny kódu vaší aplikace. V prohlížeči to používá Service Worker API. V Node.js a pro Vitest používá node-request-interceptor. Chcete-li se dozvědět více o MSW, přečtěte si jejich úvod.

Konfigurace ​

Můžete jej použít následujícím způsobem ve vašem konfiguračním souboru.

js
import { afterAll, afterEach, beforeAll } from 'vitest';
import { setupServer } from 'msw/node';
import { graphql, rest } from 'msw';

const posts = [
  {
    userId: 1,
    id: 1,
    title: 'first post title',
    body: 'first post body',
  },
  // ...
];

export const restHandlers = [
  rest.get('https://rest-endpoint.example/path/to/posts', (req, res, ctx) => {
    return res(ctx.status(200), ctx.json(posts));
  }),
];

const graphqlHandlers = [
  graphql.query(
    'https://graphql-endpoint.example/api/v1/posts',
    (req, res, ctx) => {
      return res(ctx.data(posts));
    }
  ),
];

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

// Spuštění serveru před všemi testy
beforeAll(() => server.listen({ onUnhandledRequest: 'error' }));

// Ukončení serveru po všech testech
afterAll(() => server.close());

// Reset handlerů po každém testu (důležité pro izolaci testů)
afterEach(() => server.resetHandlers());

Konfigurace serveru s onUnhandleRequest: 'error' zajišťuje, že bude vyvolána chyba, kdykoli dojde k požadavku, který nemá odpovídající obslužnou rutinu.

Příklad ​

Máme plně funkční příklad, který používá MSW: React Testing with MSW.

Více ​

S MSW toho můžete dělat mnohem více. Můžete přistupovat k souborům cookie a parametrům dotazu, definovat mockované chybové odpovědi a mnoho dalšího! Pro více informací o MSW si přečtěte dokumentaci.

Časovače ​

Když testujeme kód, který zahrnuje časové intervaly nebo intervaly, místo toho, abychom nechali naše testy čekat nebo vypršet časový limit, můžeme naše testy urychlit pomocí "falešných" časovačů, které mockují volání setTimeout a setInterval.

Podrobnější popis API naleznete v sekci vi.useFakeTimers api.

Příklad ​

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('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);
    // posun o 2ms funkci nespustí
    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);
  });
});

Cheat Sheet ​

INFO

vi v níže uvedených příkladech je importováno přímo z vitest. Můžete ho také používat globálně, pokud nastavíte globals na true ve vaší konfiguraci.

Chci…

  • Špehovat metodu instance
ts
const instance = new SomeClass();
vi.spyOn(instance, 'method');
  • Mockovat exportované proměnné
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');
  • Mockovat exportovanou funkci

Příklad použití vi.mock:

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

vi.mock('./some-path.js', () => ({
  method: vi.fn(),
}));

WARNING

Nezapomeňte, že volání vi.mock je přesunuto na začátek souboru (tzv. hoisting). Nevkládejte volání vi.mock do bloku beforeEach, protože pouze jedno z nich by skutečně mockovalo modul.

Příklad s vi.spyOn:

ts
import * as exports from './some-path.js';

vi.spyOn(exports, 'method').mockImplementation(() => {});
  • Mockovat implementaci exportované třídy

Příklad s vi.mock a prototypem:

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 };
});
// SomeClass.mock.instances bude obsahovat instance třídy SomeClass

Příklad s vi.mock a návratovou hodnotou:

ts
import { SomeClass } from './some-path.js';

vi.mock('./some-path.js', () => {
  const SomeClass = vi.fn(() => ({
    someMethod: vi.fn(),
  }));
  return { SomeClass };
});
// SomeClass.mock.returns bude obsahovat vrácené objekty

Příklad s vi.spyOn:

ts
import * as exports from './some-path.js';

vi.spyOn(exports, 'SomeClass').mockImplementation(() => {
  // cokoliv vám vyhovuje z prvních dvou příkladů
});
  • Špehovat objekt vrácený z funkce

Příklad použití cache:

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(),
      };
    }
    // nyní pokaždé, když je volána funkce useObject(), vrátí stejnou referenci objektu
    return _cache;
  };
  return { useObject };
});

const obj = useObject();
// obj.method bylo voláno uvnitř some-path
expect(obj.method).toHaveBeenCalled();
  • Mockovat část modulu
ts
import { mocked, original } from './some-path.js';

vi.mock('./some-path.js', async () => {
  const mod = await vi.importActual<typeof import('./some-path.js')>(
    './some-path.js'
  );
  return {
    ...mod,
    mocked: vi.fn(),
  };
});
original(); // má původní chování
mocked(); // je špehovací funkce
  • Mockovat aktuální datum

Pro mockování času Date můžete použít pomocnou funkci vi.setSystemTime. Tato hodnota se neresetuje automaticky mezi jednotlivými testy.

Mějte na paměti, že použití vi.useFakeTimers také změní čas Date.

ts
const mockDate = new Date(2022, 0, 1);
vi.setSystemTime(mockDate);
const now = new Date();
expect(now.valueOf()).toBe(mockDate.valueOf());
// reset mockovaného času
vi.useRealTimers();
  • Mockovat globální proměnnou

Globální proměnnou můžete nastavit přiřazením hodnoty do globalThis nebo pomocí pomocníka vi.stubGlobal. Pokud použijete vi.stubGlobal, tato hodnota se neresetuje automaticky mezi jednotlivými testy, pokud nepovolíte volbu konfigurace unstubGlobals nebo nezavoláte vi.unstubAllGlobals.

ts
vi.stubGlobal('__VERSION__', '1.0.0');
expect(__VERSION__).toBe('1.0.0');
  • Mockovat import.meta.env

Pro změnu proměnné prostředí můžete jednoduše přiřadit novou hodnotu proměnné import.meta.env. Tato hodnota se neresetuje automaticky mezi jednotlivými testy.

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

// můžete ji resetovat v beforeEach hooku manuálně
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');
});

Pokud chcete automaticky resetovat hodnotu, můžete použít pomocníka vi.stubEnv s povolenou volbou konfigurace unstubEnvs (nebo zavolat vi.unstubAllEnvs manuálně v beforeEach hooku):

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

// před spuštěním testů je "VITE_ENV" "test"
import.meta.env.VITE_ENV === 'test';

it('changes value', () => {
  vi.stubEnv('VITE_ENV', 'staging');
  expect(import.meta.env.VITE_ENV).toBe('staging');
});

it('the value is restored before running another test', () => {
  expect(import.meta.env.VITE_ENV).toBe('test');
});
ts
// vitest.config.ts
export default {
  test: {
    unstubAllEnvs: true,
  },
};
Pager
Předchozí stránkaSnímky
Další stránkaTestování typů

Vydáno pod licencí MIT.

Copyright (c) 2024 Mithril Contributors

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

Vydáno pod licencí MIT.

Copyright (c) 2024 Mithril Contributors