Türkiye'de ilk Mobil & PC Aynı Anda Metin2 Oyna. Triarchonline kalıcı ve uzun ömürlü yapısı ile 24 Temmuz'da açılıyor. | 1-99 Mobil Metin2 Triarch HEMEN TIKLA!
[NODE JS] Jest ile Mock Fonksiyon Kullanımı
Selamlar arkadaşlar, bugün Jest'in en güçlü özelliklerinden biri olan mock fonksiyonlardan bahsedeceğim. Mock kavramını ilk duyduğumda ne işe yaradığını anlamakta zorlanmıştım. Ama gerçek dünya projelerinde, özellikle dış servislere bağımlı kodları test ederken mock'ların hayat kurtardığını gördüm.
Mock fonksiyon nedir? Basitçe söylemek gerekirse, gerçek fonksiyonun yerine geçen sahte bir fonksiyondur. Neden ihtiyaç duyarız? Diyelim ki bir fonksiyonunuz veritabanına sorgu atıyor veya bir API'ye istek gönderiyor. Unit test yazarken bu dış bağımlılıkları gerçekten çalıştırmak istemezsiniz. Hem yavaştır, hem de deterministik değildir. Mock ile bu dış bağımlılıkları simüle edersiniz.
Jest'te mock fonksiyon oluşturmanın en basit yolu jest.fn() kullanmaktır. Bu size boş bir mock fonksiyon verir. mockReturnValue ile bu fonksiyonun ne döndüreceğini belirleyebilirsiniz. mockImplementation ile ise tamamen özel bir davranış tanımlayabilirsiniz. mockResolvedValue ise Promise döndüren fonksiyonlar için kullanılır.
Mock fonksiyonların en güzel yanı, çağrılma bilgilerini tutmasıdır. Kaç kez çağrıldığını, hangi parametrelerle çağrıldığını, ne döndürdüğünü kontrol edebilirsiniz. toHaveBeenCalled, toHaveBeenCalledTimes, toHaveBeenCalledWith gibi matcher'lar bu amaçla kullanılır.
Modül mock'lama da Jest'in güçlü özelliklerinden biridir. jest.mock() ile bir modülün tamamını mock'layabilirsiniz. Bu özellikle axios, fs, veritabanı driver'ları gibi modülleri test ederken çok işe yarar. Jest otomatik olarak modüldeki tüm export'ları mock fonksiyonlarla değiştirir.
Spy kavramı da mock'a benzer ama farklıdır. jest.spyOn ile mevcut bir objenin metodunu izleyebilirsiniz. Spy, orijinal implementasyonu korur ama çağrılma bilgilerini kaydeder. İsterseniz spy üzerinden implementasyonu da değiştirebilirsiniz. Test bittiğinde mockRestore ile orijinal haline döndürebilirsiniz.
Manuel mock'lar da var. Projenizin kök dizininde __mocks__ klasörü oluşturarak, belirli modüller için kalıcı mock dosyaları tanımlayabilirsiniz. Bu özellikle büyük projelerde aynı mock'u birden fazla test dosyasında kullanmanız gerektiğinde çok işe yarar.
Dikkat etmeniz gereken bir konu var: her testten sonra mock'ları sıfırlamayı unutmayın. mockClear, mockReset ve mockRestore arasındaki farkları bilmek önemlidir. mockClear çağrı bilgilerini temizler, mockReset hem çağrı bilgilerini hem de implementasyonu temizler, mockRestore ise spy'ları orijinal haline döndürür. Ben genellikle afterEach içinde jest.clearAllMocks() kullanırım.
Timer mock'ları da jest.useFakeTimers() ile mümkündür. setTimeout, setInterval gibi zamanlayıcıları mock'layabilir ve jest.advanceTimersByTime ile zamanı ileri sarabilirsiniz. Bu özellik debounce, throttle gibi fonksiyonları test ederken harikadır.
Kod:
// userService.js - Dış bağımlılıkları olan servis
const axios = require('axios');
const db = require('./database');
async function kullaniciBilgisiGetir(userId) {
const response = await axios.get('https://api.example.com/users/' + userId);
return response.data;
}
async function kullaniciKaydet(userData) {
const result = await db.insert('users', userData);
return { id: result.insertId, ...userData };
}
async function kullaniciSil(userId) {
const user = await db.findById('users', userId);
if (!user) {
throw new Error('Kullanıcı bulunamadı');
}
await db.delete('users', userId);
return { deleted: true, userId: userId };
}
module.exports = { kullaniciBilgisiGetir, kullaniciKaydet, kullaniciSil };
// userService.test.js - Mock kullanarak test
const axios = require('axios');
const db = require('./database');
const { kullaniciBilgisiGetir, kullaniciKaydet, kullaniciSil } = require('./userService');
// Modülleri mock'la
jest.mock('axios');
jest.mock('./database');
describe('User Service', () => {
afterEach(() => {
jest.clearAllMocks();
});
describe('kullaniciBilgisiGetir', () => {
test('API'den kullanıcı bilgisi çekmeli', async () => {
const mockUser = { id: 1, name: 'Ahmet', email: 'ahmet@test.com' };
axios.get.mockResolvedValue({ data: mockUser });
const result = await kullaniciBilgisiGetir(1);
expect(axios.get).toHaveBeenCalledTimes(1);
expect(axios.get).toHaveBeenCalledWith('https://api.example.com/users/1');
expect(result).toEqual(mockUser);
});
test('API hatası durumunda exception fırlatmalı', async () => {
axios.get.mockRejectedValue(new Error('Network Error'));
await expect(kullaniciBilgisiGetir(1)).rejects.toThrow('Network Error');
});
});
describe('kullaniciKaydet', () => {
test('kullanıcıyı veritabanına kaydetmeli', async () => {
const userData = { name: 'Mehmet', email: 'mehmet@test.com' };
db.insert.mockResolvedValue({ insertId: 42 });
const result = await kullaniciKaydet(userData);
expect(db.insert).toHaveBeenCalledWith('users', userData);
expect(result).toEqual({ id: 42, name: 'Mehmet', email: 'mehmet@test.com' });
});
});
describe('kullaniciSil', () => {
test('var olan kullanıcıyı silmeli', async () => {
db.findById.mockResolvedValue({ id: 1, name: 'Test' });
db.delete.mockResolvedValue(true);
const result = await kullaniciSil(1);
expect(db.findById).toHaveBeenCalledWith('users', 1);
expect(db.delete).toHaveBeenCalledWith('users', 1);
expect(result).toEqual({ deleted: true, userId: 1 });
});
test('olmayan kullanıcıyı silmeye çalışırsa hata fırlatmalı', async () => {
db.findById.mockResolvedValue(null);
await expect(kullaniciSil(999)).rejects.toThrow('Kullanıcı bulunamadı');
expect(db.delete).not.toHaveBeenCalled();
});
});
});
// jest.fn() ile manuel mock oluşturma örneği
describe('Manuel Mock Örnekleri', () => {
test('callback fonksiyonunu mock ile test etme', () => {
const mockCallback = jest.fn((x) => x * 2);
const numbers = [1, 2, 3];
numbers.forEach(mockCallback);
expect(mockCallback).toHaveBeenCalledTimes(3);
expect(mockCallback.mock.results[0].value).toBe(2);
expect(mockCallback.mock.results[1].value).toBe(4);
expect(mockCallback.mock.results[2].value).toBe(6);
});
test('spyOn ile mevcut metodu izleme', () => {
const calculator = {
add: (a, b) => a + b,
multiply: (a, b) => a * b
};
const spy = jest.spyOn(calculator, 'add');
const result = calculator.add(3, 4);
expect(spy).toHaveBeenCalledWith(3, 4);
expect(result).toBe(7);
spy.mockRestore();
});
});
Mock fonksiyonlar doğru kullanıldığında testlerinizi hem hızlandırır hem de güvenilir kılar. Ancak aşırıya kaçmayın; her şeyi mock'larsanız aslında hiçbir şeyi test etmemiş olursunuz. Gerçek entegrasyonu da integration testlerle mutlaka kontrol edin. Kolay gelsin!
Şu an konuyu görüntüleyenler (Toplam : 0, Üye: 0, Misafir: 0)
Benzer konular
- Cevaplar
- 1
- Görüntüleme
- 11
- Cevaplar
- 1
- Görüntüleme
- 11
- Cevaplar
- 1
- Görüntüleme
- 7
- Cevaplar
- 1
- Görüntüleme
- 10
- Cevaplar
- 1
- Görüntüleme
- 13
