Mocking
Test yazarken, dahili veya harici bir servisin "sahte" bir versiyonunu oluşturmanız sadece bir zaman meselesidir. Bu genellikle mocking olarak adlandırılır. Vitest, vi
yardımcısı aracılığıyla size yardımcı olacak yardımcı fonksiyonlar sağlar. Bunu vitest
'ten içe aktarabilir veya global
yapılandırması etkinse global olarak erişebilirsiniz.
WARNING
Test çalıştırmaları arasında mock durum değişikliklerini geri almak için, her test çalıştırmasından önce veya sonra mock'ları temizlemeyi veya geri yüklemeyi mutlaka unutmayın! Daha fazla bilgi için mockReset
belgelerine bakın.
vi.fn
, vi.mock
veya vi.spyOn
yöntemlerine aşina değilseniz, önce API bölümüne göz atın.
Tarihler
Bazen test yaparken tutarlılığı sağlamak için tarihi kontrol etmeniz gerekir. Vitest, zamanlayıcıları ve sistem tarihini manipüle etmek için @sinonjs/fake-timers
paketini kullanır. Belirli API hakkında daha fazla bilgiyi burada bulabilirsiniz.
Örnek
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(() => {
// vitest'e sahte zaman kullandığımızı bildir
vi.useFakeTimers();
});
afterEach(() => {
// her test çalıştırmasından sonra tarihi eski haline getir
vi.useRealTimers();
});
it('allows purchases within business hours', () => {
// mesai saatleri içinde saati ayarla
const date = new Date(2000, 1, 1, 13);
vi.setSystemTime(date);
// Date.now()'a erişim yukarıda ayarlanan tarihle sonuçlanacaktır
expect(purchase()).toEqual({ message: 'Success' });
});
it('disallows purchases outside of business hours', () => {
// mesai saatleri dışında saati ayarla
const date = new Date(2000, 1, 1, 19);
vi.setSystemTime(date);
// Date.now()'a erişim yukarıda ayarlanan tarihle sonuçlanacaktır
expect(purchase()).toEqual({ message: 'Error' });
});
});
Fonksiyonlar
Fonksiyonları mock'lamak iki farklı kategoriye ayrılabilir: spying ve mocking.
Bazen tek ihtiyacınız olan belirli bir fonksiyonun çağrılıp çağrılmadığını (ve belki hangi argümanların geçirildiğini) doğrulamaktır. Bu durumlarda doğrudan vi.spyOn()
ile kullanabileceğimiz bir spy yeterli olacaktır (daha fazlasını buradan okuyun).
Ancak spy'lar size sadece fonksiyonları izleme konusunda yardımcı olabilir, bu fonksiyonların uygulamasını değiştiremezler. Bir fonksiyonun sahte (veya mock'lanmış) bir versiyonunu oluşturmamız gereken durumlarda vi.fn()
kullanabiliriz (daha fazlasını buradan okuyun).
Fonksiyonları mock'lamak için temel olarak Tinyspy kullanıyoruz, ancak jest
uyumluluğu sağlamak amacıyla kendi sarmalayıcımızı geliştirdik. Hem vi.fn()
hem de vi.spyOn()
aynı yöntemleri paylaşır, ancak yalnızca vi.fn()
'nin dönüş sonucu çağrılabilir.
Örnek
import { afterEach, describe, expect, it, vi } from 'vitest';
const messages = {
items: [
{ message: 'Simple test message', from: 'Testman' },
// ...
],
getLatest, // destekleniyorsa bir `getter` veya `setter` da olabilir
};
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);
});
});
Daha Fazlası
Globaller
jsdom
veya node
ile bulunmayan global değişkenleri vi.stubGlobal
yardımcısını kullanarak mock'layabilirsiniz. Bu, global değişkenin değerini bir globalThis
nesnesine yerleştirecektir.
import { vi } from 'vitest';
const IntersectionObserverMock = vi.fn(() => ({
disconnect: vi.fn(),
observe: vi.fn(),
takeRecords: vi.fn(),
unobserve: vi.fn(),
}));
vi.stubGlobal('IntersectionObserver', IntersectionObserverMock);
// şimdi buna `IntersectionObserver` veya `window.IntersectionObserver` olarak erişebilirsiniz
Modüller
Mock modüller, başka bir kodda çağrılan üçüncü taraf kütüphanelerin davranışını taklit eder, böylece argümanları, çıktıyı test etmenize ve hatta uygulamasını yeniden tanımlamanıza olanak tanır.
Daha ayrıntılı bir API açıklaması için vi.mock()
API bölümüne bakın.
Otomatik Mocking Algoritması
Kodunuz, ilişkili bir __mocks__
dosyası veya bu modül için bir factory
olmadan bir modülü içe aktarıyorsa, Vitest modülün kendisini çağırarak ve her dışa aktarmayı mock'layarak otomatik olarak bir mock oluşturacaktır.
Aşağıdaki prensipler geçerlidir:
- Tüm diziler boşaltılacaktır
- Tüm ilkel tipler ve koleksiyonlar aynı kalacaktır
- Tüm nesneler derinlemesine klonlanacaktır
- Sınıfların tüm örnekleri ve prototipleri derinlemesine klonlanacaktır
Sanal Modüller
Vitest, Vite sanal modüllerini mock'lamayı destekler. Jest'te sanal modüllerin ele alınışından farklı çalışır. vi.mock
fonksiyonuna virtual: true
geçirmek yerine, modülün var olduğunu Vite'a söylemeniz gerekir, aksi takdirde ayrıştırma sırasında başarısız olur. Bunu birkaç şekilde yapabilirsiniz:
- Bir takma ad sağlayın
import { defineConfig } from 'vitest/config';
import { resolve } from 'node:path';
export default defineConfig({
test: {
alias: {
'$app/forms': resolve('./mocks/forms.js'),
},
},
});
- Sanal bir modülü çözen bir eklenti sağlayın
import { defineConfig } from 'vitest/config';
export default defineConfig({
plugins: [
{
name: 'virtual-modules',
resolveId(id) {
if (id === '$app/forms') {
return 'virtual:$app/forms';
}
},
},
],
});
İkinci yaklaşımın faydası, farklı sanal giriş noktalarını dinamik olarak oluşturabilmenizdir. Birden fazla sanal modülü tek bir dosyaya yönlendirirseniz, hepsi vi.mock
'tan etkilenecektir, bu nedenle benzersiz tanımlayıcılar kullandığınızdan emin olun.
Mocking Tuzakları
Aynı dosyanın diğer yöntemleri içinde çağrılan yöntemlere yapılan çağrıları mock'lamanın mümkün olmadığını unutmayın. Örneğin, bu kodda:
export function foo() {
return 'foo';
}
export function foobar() {
return `${foo()}bar`;
}
foo
yöntemi doğrudan referans alındığı için dışarıdan mock'lanamaz. Bu nedenle bu kodun foobar
içindeki foo
çağrısı üzerinde hiçbir etkisi olmayacaktır (ancak diğer modüllerdeki foo
çağrısını etkileyecektir):
import { vi } from 'vitest';
import * as mod from './foobar.js';
// bu sadece orijinal modülün dışındaki "foo"yu etkileyecektir
vi.spyOn(mod, 'foo');
vi.mock('./foobar.js', async importOriginal => {
return {
...(await importOriginal<typeof import('./foobar.js')>()),
// bu sadece orijinal modülün dışındaki "foo"yu etkileyecektir
foo: () => 'mocked',
};
});
Bu davranışı, foobar
yöntemine doğrudan uygulamayı sağlayarak doğrulayabilirsiniz:
import * as mod from './foobar.js';
vi.spyOn(mod, 'foo');
// dışa aktarılan foo mock'lanmış yöntemi referans alır
mod.foobar(mod.foo);
export function foo() {
return 'foo';
}
export function foobar(injectedFoo) {
return injectedFoo === foo; // false
}
Bu beklenen bir davranıştır. Mocking'in bu şekilde kullanılması genellikle kötü kodun bir işaretidir. Kodunuzu birden fazla dosyaya yeniden düzenlemeyi veya bağımlılık enjeksiyonu gibi teknikleri kullanarak uygulama mimarinizi iyileştirmeyi düşünün.
Örnek
import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest';
import { Client } from 'pg';
import { failure, success } from './handlers.js';
// todo'ları al
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 });
});
});
Dosya Sistemi
Dosya sistemini mock'lamak, testlerin gerçek dosya sistemine bağlı olmamasını sağlayarak testleri daha güvenilir ve öngörülebilir hale getirir. Bu izolasyon sayesinde önceki testlerden kaynaklanan yan etkilerden kaçınılması kolaylaşır. İzin sorunları, disk dolu senaryoları veya okuma/yazma hataları gibi gerçek bir dosya sistemiyle çoğaltılması zor veya imkansız olabilecek hata koşullarını ve uç durumları test etmeye olanak tanır.
Vitest, varsayılan olarak herhangi bir dosya sistemi mocking API'si sağlamaz. fs
modülünü manuel olarak mock'lamak için vi.mock
kullanabilirsiniz, ancak bunu sürdürmek zordur. Bunun yerine, bunu sizin için yapması için memfs
kullanmanızı öneririz. memfs
, gerçek diske dokunmadan dosya sistemi işlemlerini simüle eden bellek içi bir dosya sistemi oluşturur. Bu yaklaşım hızlı ve güvenlidir, gerçek dosya sistemi üzerindeki olası yan etkileri önler.
Örnek
Her fs
çağrısını memfs
'e otomatik olarak yönlendirmek için projenizin kökünde __mocks__/fs.cjs
ve __mocks__/fs/promises.cjs
dosyalarını oluşturabilirsiniz:
// `import` da kullanabiliriz, ancak o zaman
// her dışa aktarma açıkça tanımlanmalıdır
const { fs } = require('memfs');
module.exports = fs;
// `import` da kullanabiliriz, ancak o zaman
// her dışa aktarma açıkça tanımlanmalıdır
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';
// vitest'e __mocks__ klasöründen fs mock'unu kullanmasını söyle
// fs her zaman mock'lanacaksa bu bir kurulum dosyasında yapılabilir
vi.mock('node:fs');
vi.mock('node:fs/promises');
beforeEach(() => {
// bellek içi fs'nin durumunu sıfırla
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', () => {
// birden fazla dosya tanımlamak için vol.fromJSON kullanabilirsiniz
vol.fromJSON(
{
'./dir1/hw.txt': 'hello dir1',
'./dir2/hw.txt': 'hello dir2',
},
// varsayılan cwd
'/tmp'
);
expect(readHelloWorld('/tmp/dir1/hw.txt')).toBe('hello dir1');
expect(readHelloWorld('/tmp/dir2/hw.txt')).toBe('hello dir2');
});
İstekler
Vitest Node'da çalıştığı için ağ isteklerini mock'lamak zordur; web API'leri mevcut değildir, bu nedenle bizim için ağ davranışını taklit edecek bir şeye ihtiyacımız var. Bunu başarmak için Mock Service Worker kullanmanızı öneririz. http
, WebSocket
ve GraphQL
ağ isteklerini mock'lamanıza olanak tanır ve çerçeve bağımsızdır.
Mock Service Worker (MSW), testlerinizin yaptığı istekleri yakalayarak çalışır ve uygulama kodunuzda herhangi bir değişiklik yapmadan kullanmanıza olanak tanır. Tarayıcıda bu, Service Worker API'sini kullanır. Node.js'de ve Vitest için @mswjs/interceptors
kütüphanesini kullanır. MSW hakkında daha fazla bilgi edinmek için girişlerini okuyun.
Yapılandırma
Kurulum dosyanızda aşağıdaki gibi kullanabilirsiniz:
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);
// Tüm testlerden önce sunucuyu dinlemeye başla
beforeAll(() => server.listen({ onUnhandledRequest: 'error' }));
// Tüm testlerden sonra sunucuyu kapat
afterAll(() => server.close());
// Test izolasyonu için her testten sonra işleyicileri resetle
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);
// Tüm testlerden önce sunucuyu dinlemeye başla
beforeAll(() => server.listen({ onUnhandledRequest: 'error' }));
// Tüm testlerden sonra sunucuyu kapat
afterAll(() => server.close());
// Test izolasyonu için her testten sonra işleyicileri resetle
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);
// Alınan mesajı istemciye geri gönder
client.send(`Server received: ${event.data}`);
});
}),
];
const server = setupServer(...wsHandlers);
// Tüm testlerden önce sunucuyu dinlemeye başla
beforeAll(() => server.listen({ onUnhandledRequest: 'error' }));
// Tüm testlerden sonra sunucuyu kapat
afterAll(() => server.close());
// Test izolasyonu için her testten sonra işleyicileri resetle
afterEach(() => server.resetHandlers());
Sunucuyu
onUnhandledRequest: 'error'
ile yapılandırmak, karşılık gelen bir istek işleyicisi olmayan bir istek olduğunda bir hata fırlatılmasını sağlar.
Daha Fazlası
MSW hakkında çok daha fazlası var. Çerezlere ve sorgu parametrelerine erişebilir, mock hata yanıtları tanımlayabilir ve çok daha fazlasını yapabilirsiniz! MSW ile yapabileceklerinizin tamamını görmek için belgelerini okuyun.
Zamanlayıcılar
Zaman aşımları veya aralıkları içeren kodu test ettiğimizde, testlerimizin beklemesi veya zaman aşımına uğraması yerine, setTimeout
ve setInterval
çağrılarını mock'layan "sahte" zamanlayıcılar kullanarak testlerimizi hızlandırabiliriz.
Ayrıntılı bir API açıklaması için vi.useFakeTimers
API bölümüne bakın.
Örnek
import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest';
function executeAfterTwoHours(func) {
setTimeout(func, 1000 * 60 * 60 * 2); // 2 saat
}
function executeEveryMinute(func) {
setInterval(func, 1000 * 60); // 1 dakika
}
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 ilerletmek fonksiyonu çalıştırmaz
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);
});
});
Sınıflar
Tüm sınıflar aynı zamanda fonksiyonlar olduğu için, tek bir vi.fn
çağrısıyla tüm bir sınıfı mock'layabilirsiniz - bu doğrudan çalışır. Şu anda Vitest'in new
anahtar kelimesini dikkate almadığını unutmayın, bu nedenle bir fonksiyonun gövdesinde new.target
her zaman undefined
'dır.
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() {}
}
Bu sınıfı ES5 fonksiyonlarıyla yeniden oluşturabiliriz:
const Dog = vi.fn(function (name) {
this.name = name;
// yapıcıda örnek yöntemleri mock'la, her örnek kendi spy'ına sahip olacaktır
this.greet = vi.fn(() => `Hi! My name is ${this.name}!`);
});
// statik yöntemlerin doğrudan fonksiyon üzerinde mock'landığına dikkat edin,
// sınıfın örneği üzerinde değil
Dog.getType = vi.fn(() => 'mocked animal');
// bir sınıfın her örneğinde "speak" ve "feed" yöntemlerini mock'la
// tüm `new Dog()` örnekleri bu spy'ları miras alacak ve paylaşacaktır
Dog.prototype.speak = vi.fn(() => 'loud bark!');
Dog.prototype.feed = vi.fn();
WARNING
Yapıcı fonksiyondan ilkel olmayan bir değer döndürülürse, bu değer yeni ifadenin sonucu olacaktır. Bu durumda [[Prototype]]
doğru şekilde bağlanmayabilir:
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!
NE ZAMAN KULLANILIR?
Genel olarak, sınıf başka bir modülden yeniden dışa aktarılıyorsa, bir sınıfı modül fabrikası içinde bu şekilde yeniden oluşturursunuz:
import { Dog } from './dog.js';
vi.mock(import('./dog.js'), () => {
const Dog = vi.fn();
Dog.prototype.feed = vi.fn();
// ... diğer mock'lar
return { Dog };
});
Bu yöntem, aynı arayüzü kabul eden bir fonksiyona bir sınıf örneği geçirmek için de kullanılabilir:
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);
});
Şimdi, Dog
sınıfının yeni bir örneğini oluşturduğumuzda, speak
yöntemi ( feed
ve greet
ile birlikte) zaten mock'lanmıştır:
const Cooper = new Dog('Cooper');
Cooper.speak(); // loud bark!
Cooper.greet(); // Hi! My name is Cooper!
// çağrının geçerliliğini kontrol etmek için yerleşik assertion'ları kullanabilirsiniz
expect(Cooper.speak).toHaveBeenCalled();
expect(Cooper.greet).toHaveBeenCalled();
const Max = new Dog('Max');
// prototipe atanan yöntemler örnekler arasında paylaşılır
expect(Max.speak).toHaveBeenCalled();
expect(Max.greet).not.toHaveBeenCalled();
Belirli bir örnek için dönüş değerini yeniden atayabiliriz:
const dog = new Dog('Cooper');
// "vi.mocked" bir tür yardımcısıdır, çünkü
// TypeScript, Dog'un mock'lanmış bir sınıf olduğunu bilmediği için,
// fonksiyonun mock olup olmadığını doğrulamadan herhangi bir fonksiyonu MockInstance<T> türüne sarar
vi.mocked(dog.speak).mockReturnValue('woof woof');
dog.speak(); // woof woof
Özelliği mock'lamak için vi.spyOn(dog, 'name', 'get')
yöntemini kullanabiliriz. Bu, mock'lanmış özellik üzerinde spy assertion'ları kullanmayı mümkün kılar:
const dog = new Dog('Cooper');
const nameSpy = vi.spyOn(dog, 'name', 'get').mockReturnValue('Max');
expect(dog.name).toBe('Max');
expect(nameSpy).toHaveBeenCalledTimes(1);
TIP
Aynı yöntemi kullanarak getter ve setter'ları da spy'layabilirsiniz.
Hızlı Başvuru
INFO
Aşağıdaki örneklerde vi
doğrudan vitest
'ten içe aktarılmıştır. Yapılandırmanızda globals
'ı true
olarak ayarlarsanız global olarak da kullanabilirsiniz.
İstiyorum ki…
Dışa aktarılan değişkenleri mock'la
export const getter = 'variable';
import * as exports from './example.js';
vi.spyOn(exports, 'getter', 'get').mockReturnValue('mocked');
Dışa aktarılan bir fonksiyonu mock'la
vi.mock
ile örnek:
WARNING
vi.mock
çağrısının dosyanın en üstüne taşındığını unutmayın. Her zaman tüm içe aktarmalardan önce yürütülecektir.
export function method() {}
import { method } from './example.js';
vi.mock('./example.js', () => ({
method: vi.fn(),
}));
vi.spyOn
ile örnek:
import * as exports from './example.js';
vi.spyOn(exports, 'method').mockImplementation(() => {});
Dışa aktarılan bir sınıf uygulamasını mock'la
vi.mock
ve.prototype
ile örnek:
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'a sahip olacak.
vi.spyOn
ile örnek:
import * as mod from './example.js';
const SomeClass = vi.fn();
SomeClass.prototype.someMethod = vi.fn();
vi.spyOn(mod, 'SomeClass').mockImplementation(SomeClass);
Bir fonksiyondan dönen bir nesne üzerinde spy kullan
- Önbellek kullanarak örnek:
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(),
};
}
// şimdi useObject() her çağrıldığında
// aynı nesne referansını döndürecektir
return _cache;
};
return { useObject };
});
const obj = useObject();
// obj.method some-path içerisinde çağrıldı
expect(obj.method).toHaveBeenCalled();
Bir modülün bir kısmını mock'la
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(); // orijinal davranışa sahip
mocked(); // bir spy fonksiyonudur
WARNING
Bunun yalnızca harici erişimi mock'ladığını unutmayın. Bu örnekte, original
dahili olarak mocked
'ı çağırırsa, her zaman modülde tanımlanan fonksiyonu çağıracaktır, mock fabrikası içindeki fonksiyonu değil.
Geçerli tarihi mock'la
Date
'in zamanını mock'lamak için vi.setSystemTime
yardımcı fonksiyonunu kullanabilirsiniz. Bu değer farklı testler arasında otomatik olarak sıfırlanmayacaktır.
vi.useFakeTimers
kullanmanın Date
'in zamanını da değiştirdiğini unutmayın.
const mockDate = new Date(2022, 0, 1);
vi.setSystemTime(mockDate);
const now = new Date();
expect(now.valueOf()).toBe(mockDate.valueOf());
// mock'lanmış zamanı sıfırla
vi.useRealTimers();
Global bir değişkeni mock'la
Global değişkeni globalThis
'e bir değer atayarak veya vi.stubGlobal
yardımcısını kullanarak ayarlayabilirsiniz. vi.stubGlobal
kullanırken, unstubGlobals
yapılandırma seçeneğini etkinleştirmediğiniz veya vi.unstubAllGlobals
çağrısı yapmadığınız sürece farklı testler arasında otomatik olarak sıfırlanmayacaktır.
vi.stubGlobal('__VERSION__', '1.0.0');
expect(__VERSION__).toBe('1.0.0');
import.meta.env
'i mock'la
- Ortam değişkenini değiştirmek için, ona yeni bir değer atayabilirsiniz.
WARNING
Ortam değişkeni değeri farklı testler arasında otomatik olarak resetlenmeyecektir.
import { beforeEach, expect, it } from 'vitest';
// testleri çalıştırmadan önce "VITE_ENV" 'test' değerindedir
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');
});
- Değeri/değerleri otomatik olarak resetlemek isterseniz,
unstubEnvs
yapılandırma seçeneği etkinleştirilmiş olarak (veyabeforeEach
kancasındavi.unstubAllEnvs
manuel olarak çağırarak)vi.stubEnv
yardımcısını kullanabilirsiniz:
import { expect, it, vi } from 'vitest';
// testleri çalıştırmadan önce "VITE_ENV" 'test' değerindedir
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 an other test', () => {
expect(import.meta.env.VITE_ENV).toBe('test');
});
export default defineConfig({
test: {
unstubEnvs: true,
},
});