Jest ile Asenkron Testler: Modern Yaklaşımlar ve En İyi Uygulamalar
Giriş
Yazılım geliştirme dünyasında, özellikle modern web uygulamalarında, asenkron programlama vazgeçilmez bir yer tutar. Veritabanı işlemleri, ağ istekleri (API çağrıları), dosya okuma/yazma veya zamanlayıcılar gibi birçok işlem, uygulamanın ana iş parçacığını (main thread) bloke etmeden arka planda çalışır. Bu sayede kullanıcı arayüzleri donmaz ve daha akıcı bir kullanıcı deneyimi sunulur. Ancak asenkron kodun doğası gereği, bu tür kod bloklarını test etmek senkron kodlara göre daha fazla dikkat ve özel yaklaşımlar gerektirir. Bir fonksiyonun bir değeri anında döndürmesi yerine, bir süre sonra bir sonuç üretmesi veya bir hata fırlatması durumu, test çerçevelerinin bu bekleme sürecini doğru yönetmesini gerektirir.
Jest, Facebook tarafından geliştirilen ve özellikle React uygulamaları başta olmak üzere geniş bir JavaScript projesi yelpazesinde tercih edilen güçlü ve popüler bir test çerçevesidir. Hızlı, kullanımı kolay ve zengin özellik setine sahip olmasıyla öne çıkar. Jest’in en güçlü yanlarından biri de asenkron kodları test etme konusundaki yetenekleridir. Bu makalede, Jest kullanarak asenkron JavaScript kodlarını nasıl etkin bir şekilde test edebileceğimizi, farklı yaklaşımları, en iyi uygulamaları ve sık karşılaşılan senaryoları detaylı bir şekilde inceleyeceğiz.
Asenkron JavaScript’in Temelleri
Jest ile asenkron testlere dalmadan önce, JavaScript’teki asenkron programlama paradigmalarını anlamak önemlidir.
Callback’ler
Asenkron JavaScript’in ilk ve en temel yaklaşımlarından biri callback fonksiyonlarıdır. Bir asenkron işlem tamamlandığında çağrılacak olan bir fonksiyonu parametre olarak geçirme prensibine dayanır.
function fetchData(callback) {
setTimeout(() => {
callback(null, 'Veri başarıyla alındı!');
}, 1000);
}
fetchData((error, data) => {
if (error) {
console.error(error);
} else {
console.log(data); // "Veri başarıyla alındı!"
}
});
Callback’ler basit durumlar için yeterli olsa da, iç içe geçmiş asenkron işlemler (“callback hell”) kodun okunabilirliğini ve yönetilebilirliğini zorlaştırabilir.
Promise’ler
ES6 ile birlikte hayatımıza giren Promise’ler, callback hell sorununa modern bir çözüm sunmuştur. Bir Promise, asenkron bir işlemin nihai sonucunu (başarılı ya da başarısız) temsil eden bir nesnedir. Üç ana durumu vardır:
* Pending (Beklemede): İşlem henüz tamamlanmamıştır.
* Fulfilled/Resolved (Başarılı): İşlem başarıyla tamamlandı ve bir değer döndürdü.
* Rejected (Reddedildi): İşlem bir hata ile sonuçlandı.
Promise’ler, .then(), .catch() ve .finally() metotları ile zincirlenebilir bir yapı sunar.
function fetchDataPromise() {
return new Promise((resolve, reject) => {
setTimeout(() => {
const success = true; // Simülasyon: Başarılı veya başarısız
if (success) {
resolve('Veri Promise ile başarıyla alındı!');
} else {
reject('Veri Promise ile alınamadı!');
}
}, 1000);
});
}
fetchDataPromise()
.then(data => console.log(data))
.catch(error => console.error(error))
.finally(() => console.log('İşlem tamamlandı.'));
Async/Await: Modern ve Okunabilir Yaklaşım
ES2017 ile gelen async/await sözdizimi, Promise’ler üzerine inşa edilmiş sentaktik bir şekerdir. Asenkron kodu senkron gibi yazma olanağı sunarak okunabilirliği büyük ölçüde artırır.
* async anahtar kelimesi, bir fonksiyonun asenkron olduğunu ve her zaman bir Promise döndüreceğini belirtir.
* await anahtar kelimesi ise yalnızca async fonksiyonlar içinde kullanılabilir ve bir Promise’in çözülmesini (resolve veya reject olmasını) bekler. await kullanıldığında, Promise çözülene kadar fonksiyonun yürütülmesi duraklatılır ve Promise çözüldüğünde değerini döndürür veya bir hata fırlatır.
async function fetchDataAsync() {
return new Promise((resolve) => {
setTimeout(() => {
resolve('Veri async/await ile başarıyla alındı!');
}, 1000);
});
}
async function processData() {
try {
const data = await fetchDataAsync();
console.log(data); // "Veri async/await ile başarıyla alındı!"
} catch (error) {
console.error(error);
} finally {
console.log('Async/await işlemi tamamlandı.');
}
}
processData();
async/await, günümüzde asenkron JavaScript kodları yazmak için tercih edilen en modern ve okunabilir yaklaşımdır.
Jest’in Asenkron Test Yaklaşımları
Jest, yukarıda bahsedilen tüm asenkron programlama paradigmalarını destekler ve test etmeyi kolaylaştırır. İşte Jest’in sunduğu temel yaklaşımlar:
Promise Döndürmek
Jest, bir test fonksiyonundan bir Promise döndürüldüğünde, o Promise’in çözülmesini veya reddedilmesini otomatik olarak bekler. Promise başarılı olursa test geçer, reddedilirse test başarısız olur. Bu, Promise tabanlı asenkron kodları test etmenin en temel ve yaygın yollarından biridir.
Başarılı Promise’leri Test Etmek
// myModule.js
function fetchData() {
return new Promise(resolve => {
setTimeout(() => resolve('peanut butter'), 100);
});
}
// myModule.test.js
test('the data is peanut butter', () => {
return fetchData().then(data => {
expect(data).toBe('peanut butter');
});
});
Bu örnekte, fetchData fonksiyonu bir Promise döndürüyor. Jest, bu Promise’in çözülmesini bekleyecek ve .then() bloğundaki expect ifadesi çalıştıktan sonra testin tamamlandığını anlayacaktır.
Reddedilen Promise’leri Test Etmek
Bir Promise’in hata ile sonuçlandığı durumları test etmek için .catch() bloğunu kullanırız. Ancak burada önemli bir nokta var: Jest’in bir Promise’in reddedilmesini beklediğini ve testin başarısız olmamasını sağlamak için expect.assertions(n) kullanmak iyi bir pratiktir. Bu, .catch() bloğunun gerçekten çalıştığından ve içinde en az bir assertion’ın (beklenti) gerçekleştiğinden emin olmamızı sağlar. Aksi takdirde, Promise reddedilmezse veya .catch() bloğu bir şekilde atlanırsa, test başarıyla tamamlanmış gibi görünebilir (çünkü herhangi bir hata fırlatılmaz).
// myModule.js
function fetchError() {
return new Promise((resolve, reject) => {
setTimeout(() => reject('error'), 100);
});
}
// myModule.test.js
test('the fetch fails with an error', () => {
expect.assertions(1); // En az 1 assertion'ın çalışacağını belirtiriz
return fetchError().catch(e => expect(e).toMatch('error'));
});
Async/Await ile Test Etmek
async/await sözdizimi, asenkron testleri yazmayı daha da kolaylaştırır ve okunabilirliği artırır. Jest, async anahtar kelimesiyle tanımlanmış test fonksiyonlarını otomatik olarak tanır ve içindeki await ifadelerinin tamamlanmasını bekler.
Başarılı Durumları async/await ile Test Etmek
// myModule.js (aynı fetchData fonksiyonu)
function fetchData() {
return new Promise(resolve => {
setTimeout(() => resolve('peanut butter'), 100);
});
}
// myModule.test.js
test('the data is peanut butter with async/await', async () => {
const data = await fetchData();
expect(data).toBe('peanut butter');
});
test('the data is peanut butter with async/await and .resolves', async () => {
await expect(fetchData()).resolves.toBe('peanut butter');
});
await expect(promise).resolves.toBe(value) kullanımı, Promise’in başarılı bir şekilde çözülmesini ve belirli bir değeri döndürmesini beklediğimizi açıkça belirtir. Bu, hata yönetimi yapmadan başarılı senaryoları test etmek için çok temiz bir yoldur.
Hata Durumlarını async/await ile Test Etmek
Hata durumlarını async/await ile test ederken, try...catch bloğunu kullanabilir veya Jest’in özel eşleştiricisi .rejects‘i tercih edebiliriz. .rejects kullanımı genellikle daha okunabilir ve pratiktir.
// myModule.js (aynı fetchError fonksiyonu)
function fetchError() {
return new Promise((resolve, reject) => {
setTimeout(() => reject('error'), 100);
});
}
// myModule.test.js
test('the fetch fails with an error using async/await and try/catch', async () => {
expect.assertions(1);
try {
await fetchError();
} catch (e) {
expect(e).toMatch('error');
}
});
test('the fetch fails with an error using async/await and .rejects', async () => {
await expect(fetchError()).rejects.toMatch('error');
});
.rejects eşleştiricisi, beklenen Promise’in reddedilmesini ve belirtilen hata mesajını veya hata nesnesini içermesini sağlar. Bu yöntem, try...catch bloğuna göre daha özlüdür ve genellikle tercih edilir.
done() Callback Kullanımı (Eski Yaklaşım ve Özel Durumlar)
Jest’in asenkron testler için sunduğu bir diğer yöntem de done() callback’idir. Eğer test fonksiyonunuz bir Promise döndürmüyorsa veya async olarak işaretlenmemişse, Jest testin ne zaman bittiğini bilemez. Bu durumda, test fonksiyonunuza bir done argümanı ekleyebilir ve asenkron işleminiz tamamlandığında bu done() fonksiyonunu çağırarak Jest’e testin bittiğini bildirebilirsiniz.
Ne İşe Yarar?
done() callback’i, özellikle Promise tabanlı olmayan (örneğin, sadece callback tabanlı) asenkron kodları test ederken veya belirli olay dinleyicilerinin tetiklenmesini beklerken kullanışlıdır.
// myModule.js
function fetchDataWithCallback(callback) {
setTimeout(() => {
callback('lemon');
}, 100);
}
// myModule.test.js
test('the data is lemon (with done callback)', done => {
function callback(data) {
try {
expect(data).toBe('lemon');
done(); // Testin bittiğini Jest'e bildirir
} catch (error) {
done(error); // Hata durumunda Jest'e hatayı bildirir
}
}
fetchDataWithCallback(callback);
});
Neden Genellikle Kaçınılmalı?
done() callback’i, Promise’ler ve async/await varken genellikle önerilmez çünkü:
1. Unutulma Riski: done()‘ı çağırmayı unutursanız, Jest testin tamamlanmasını sonsuza kadar bekler ve sonunda bir zaman aşımı hatası verir.
2. Okunabilirlik: Promise zincirleri veya async/await yapısı genellikle daha temiz ve okunabilirdir.
3. Hata Yönetimi: Hata durumlarında done(error) çağırmak gerekirken, Promise’ler hataları doğal olarak yayar ve async/await ile try...catch bu durumu daha zarif yönetir.
Ne Zaman Kullanılabilir?
Nadiren de olsa, bazı eski kütüphanelerle çalışırken veya Promise’lere dönüştürülmesi zor olan, saf callback tabanlı veya olay odaklı asenkron senaryolarda done() kullanmak gerekebilir. Ancak mümkün olduğunca Promise döndürme veya async/await kullanma yaklaşımını tercih etmelisiniz.
Jest’in Asenkron Eşleştiricileri (Matchers)
Jest, asenkron Promise’leri test etmek için özel eşleştiriciler sunar. Bu eşleştiriciler, Promise’in çözülme veya reddedilme durumunu daha okunaklı ve güvenli bir şekilde kontrol etmenizi sağlar.
.resolves
.resolves eşleştiricisi, bir Promise’in başarıyla çözülmesini ve belirli bir değerle sonuçlanmasını beklediğinizi belirtir. Bu eşleştiriciyi await expect() ile birlikte kullanmalısınız.
// myModule.js
function getUserName(id) {
return new Promise((resolve, reject) => {
setTimeout(() => {
if (id === 1) {
resolve('Alice');
} else {
reject('User not found');
}
}, 50);
});
}
// myModule.test.js
test('getUserName resolves to Alice for id 1', async () => {
await expect(getUserName(1)).resolves.toBe('Alice');
});
.rejects
.rejects eşleştiricisi, bir Promise’in bir hata ile reddedilmesini beklediğinizi belirtir. Bu eşleştiriciyi de await expect() ile birlikte kullanmalısınız.
// myModule.test.js
test('getUserName rejects with "User not found" for id 2', async () => {
await expect(getUserName(2)).rejects.toBe('User not found');
});
test('getUserName rejects with an Error instance for invalid id', async () => {
function getUserError(id) {
return new Promise((resolve, reject) => {
setTimeout(() => {
if (id === 1) {
resolve('Alice');
} else {
reject(new Error('Invalid user ID'));
}
}, 50);
});
}
await expect(getUserError(2)).rejects.toBeInstanceOf(Error);
await expect(getUserError(2)).rejects.toHaveProperty('message', 'Invalid user ID');
});
.rejects ile birlikte toBeInstanceOf, toThrow, toMatch gibi diğer eşleştiricileri de kullanabilirsiniz.
Zaman Tabanlı Asenkron İşlemleri Test Etmek
setTimeout, setInterval, clearTimeout, clearInterval gibi zamanlayıcı fonksiyonları, asenkron JavaScript’in önemli bir parçasıdır. Bu tür fonksiyonları içeren kodları test etmek, genellikle gerçek zamanı beklemek istemediğimiz için zorlayıcı olabilir. Jest, bu durumu jest.useFakeTimers() ile çözüme kavuşturur.
jest.useFakeTimers()
Bu fonksiyon, JavaScript’in yerleşik zamanlayıcılarını Jest’in kendi “sahte” zamanlayıcılarıyla değiştirir. Bu sayede, testlerinizin gerçek zamanı beklemesine gerek kalmaz ve zamanı manuel olarak ileri sarabilirsiniz.
jest.advanceTimersByTime() ve jest.runAllTimers()
* jest.advanceTimersByTime(ms): Zamanı belirtilen milisaniye kadar ileri sarar ve bu süre içinde planlanmış tüm zamanlayıcıları çalıştırır.
* jest.runAllTimers(): Zamanı olabilecek en ileri noktaya sarar ve bekleyen tüm zamanlayıcıları (setTimeout, setInterval) anında çalıştırır.
* jest.runOnlyPendingTimers(): Sadece o an için bekleyen zamanlayıcıları çalıştırır, ileriye dönük yeni zamanlayıcılar oluşturulsa bile onları çalıştırmaz.
Örnek: Debounce Fonksiyonu Testi
Bir debounce fonksiyonu, belirli bir süre içinde art arda çağrıldığında, sadece son çağrının belirli bir gecikmeden sonra çalışmasını sağlar. Bu, kullanıcı girişi gibi durumlarda performansı artırmak için yaygın olarak kullanılır.
// utils.js
function debounce(func, delay) {
let timeout;
return function(...args) {
const context = this;
clearTimeout(timeout);
timeout = setTimeout(() => func.apply(context, args), delay);
};
}
// utils.test.js
describe('debounce', () => {
beforeEach(() => {
jest.useFakeTimers(); // Sahte zamanlayıcıları etkinleştir
});
afterEach(() => {
jest.runOnlyPendingTimers(); // Bekleyen tüm zamanlayıcıları temizle
jest.useRealTimers(); // Gerçek zamanlayıcılara geri dön
});
test('should debounce the function call', () => {
const func = jest.fn();
const debouncedFunc = debounce(func, 1000);
debouncedFunc();
debouncedFunc();
debouncedFunc(); // Üç kez çağrıldı
// Henüz zaman geçmediği için func çağrılmamış olmalı
expect(func).not.toHaveBeenCalled();
jest.advanceTimersByTime(500); // 500ms ileri sar
expect(func).not.toHaveBeenCalled(); // Hala çağrılmamış olmalı
jest.advanceTimersByTime(500); // Toplamda 1000ms ileri sarıldı
expect(func).toHaveBeenCalledTimes(1); // Sadece bir kez çağrılmış olmalı
// Yeni bir çağrı yapıp tekrar test edelim
debouncedFunc();
jest.advanceTimersByTime(1000);
expect(func).toHaveBeenCalledTimes(2);
});
});
Bu örnekte, jest.useFakeTimers() sayesinde setTimeout fonksiyonunu manuel olarak kontrol edebiliyoruz. jest.advanceTimersByTime() ile zamanı istediğimiz kadar ileri sararak, debounce fonksiyonunun doğru çalıştığını, yani belirli bir gecikmeden sonra sadece bir kez çağrıldığını doğrulayabiliyoruz. beforeEach ve afterEach bloklarında fake timer’ları etkinleştirip devre dışı bırakmak, testlerin izole kalmasını sağlar.
Asenkron İşlemleri Taklit Etmek (Mocking)
Testlerde, dış bağımlılıkları (API’ler, veritabanları, harici servisler vb.) gerçek haliyle kullanmak yerine taklit etmek (mocking), testlerin daha hızlı, güvenilir ve izole olmasını sağlar. Jest, asenkron fonksiyonları taklit etmek için güçlü araçlar sunar.
Neden Mocking Yaparız?
* İzolasyon: Testin sadece kendi birimini test etmesini sağlamak.
* Hız: Gerçek ağ istekleri veya veritabanı sorguları yavaş olabilir.
* Kontrol: Dış servislerin her zaman istediğimiz yanıtı vermediği durumları simüle etmek.
* Maliyet: Bazı API çağrıları maliyetli olabilir.
jest.fn()
jest.fn() ile basit taklit fonksiyonları oluşturabiliriz. Bu fonksiyonlar, kaç kez çağrıldıkları, hangi argümanlarla çağrıldıkları gibi bilgileri kaydeder.
mockResolvedValue() ve mockRejectedValue()
Bu metotlar, bir taklit fonksiyonunun Promise döndüren asenkron bir işlemi simüle etmesi için kullanılır.
* mockResolvedValue(value): Taklit fonksiyonunun çağrıldığında, Promise’in belirtilen value ile başarılı bir şekilde çözülmesini sağlar.
* mockRejectedValue(error): Taklit fonksiyonunun çağrıldığında, Promise’in belirtilen error ile reddedilmesini sağlar.
Örnek: API Çağrısını Taklit Etmek (fetch veya axios)
Bir kullanıcı listesi getiren bir servisimiz olduğunu varsayalım. Bu servisin gerçek bir API’ye istek attığını düşünelim.
// userService.js
import axios from 'axios';
async function getUsers() {
const response = await axios.get('https://api.example.com/users');
return response.data;
}
// userService.test.js
import axios from 'axios';
import { getUsers } from './userService';
// axios'u taklit ediyoruz
jest.mock('axios');
describe('getUsers', () => {
test('should fetch users successfully', async () => {
const mockUsers = [{ id: 1, name: 'Alice' }, { id: 2, name: 'Bob' }];
// axios.get çağrıldığında belirli bir Promise'i çözmesini sağlıyoruz
axios.get.mockResolvedValue({ data: mockUsers });
const users = await getUsers();
expect(users).toEqual(mockUsers);
expect(axios.get).toHaveBeenCalledWith('https://api.example.com/users');
});
test('should handle fetch error', async () => {
const errorMessage = 'Network Error';
// axios.get çağrıldığında bir Promise'i hata ile reddetmesini sağlıyoruz
axios.get.mockRejectedValue(new Error(errorMessage));
await expect(getUsers()).rejects.toThrow(errorMessage);
expect(axios.get).toHaveBeenCalledWith('https://api.example.com/users');
});
});
Bu örnekte, jest.mock('axios') ile axios modülünü tamamen taklit ediyoruz. Ardından axios.get.mockResolvedValue ve axios.get.mockRejectedValue kullanarak, getUsers fonksiyonunun içindeki axios.get çağrısının gerçek bir ağ isteği yapmasını engelliyor ve istediğimiz yanıtları döndürmesini sağlıyoruz. Bu, testlerimizin hızlı ve dış bağımlılıklardan arınmış olmasını garanti eder.
mockImplementation()
Daha karmaşık taklit senaryoları için mockImplementation() kullanılabilir. Bu metot, taklit fonksiyonunun ne yapacağını tam olarak kontrol etmenizi sağlar.
// userService.test.js (mockImplementation örneği)
import axios from 'axios';
import { getUsers } from './userService';
jest.mock('axios');
test('should return different data based on arguments with mockImplementation', async () => {
axios.get.mockImplementation((url) => {
if (url === 'https://api.example.com/users') {
return Promise.resolve({ data: [{ id: 1, name: 'Charlie' }] });
}
if (url === 'https://api.example.com/products') {
return Promise.resolve({ data: [{ id: 101, name: 'Laptop' }] });
}
return Promise.reject(new Error('Not Found'));
});
const users = await getUsers(); // getUsers fonksiyonu https://api.example.com/users'ı çağırıyor
expect(users).toEqual([{ id: 1, name: 'Charlie' }]);
// Farklı bir URL ile çağrıldığında ne olacağını test etmek için
const getProducts = async () => {
const response = await axios.get('https://api.example.com/products');
return response.data;
};
const products = await getProducts();
expect(products).toEqual([{ id: 101, name: 'Laptop' }]);
});
Asenkron Testlerde En İyi Uygulamalar
Asenkron testler yazarken verimliliği ve güvenilirliği artırmak için bazı en iyi uygulamalar şunlardır:
async/await Tercih Edin
Mümkün olduğunca async/await kullanın. Promise tabanlı kodları test etmenin en okunaklı, modern ve yönetilebilir yoludur. Callback tabanlı kodları bile bir Promise’e sarmalayarak async/await ile test edebilirsiniz.
expect.assertions(n) Kullanın
Özellikle try...catch blokları içinde veya Promise’in reddedilme durumlarını test ederken expect.assertions(n) kullanmak, testin beklediğiniz sayıda assertion’ı gerçekten çalıştırdığından emin olmanızı sağlar. Bu, asenkron bir kodun beklenmedik bir şekilde başarısız olması durumunda testin yanlışlıkla “geçti” olarak işaretlenmesini engeller.
done() ve Promise/Async-Await’i Karıştırmayın
Bir test fonksiyonu hem bir Promise döndürüyor hem de done() callback’ini çağırıyorsa, Jest kararsız davranışlar sergileyebilir. Her test için tek bir asenkron yönetim stratejisi seçin: ya Promise döndürün (veya async kullanın) ya da done() callback’ini kullanın, ikisini birden değil.
Testleri İzole Edin (beforeEach, afterEach)
beforeEach ve afterEach kancalarını kullanarak her testten önce gerekli kurulumları yapın (örneğin, sahte zamanlayıcıları etkinleştirme) ve her testten sonra temizlik işlemlerini (örneğin, sahte zamanlayıcıları sıfırlama, taklitleri temizleme) gerçekleştirin. Bu, testlerin birbirini etkilemesini engeller ve güvenilirliği artırır.
describe('My Async Module', () => {
beforeEach(() => {
jest.useFakeTimers();
// Diğer kurulumlar (örneğin, taklitleri sıfırlama)
});
afterEach(() => {
jest.runOnlyPendingTimers();
jest.useRealTimers();
jest.clearAllMocks(); // Tüm taklit çağrılarını temizle
});
// Testler buraya gelecek
});
Jest’in Varsayılan Zaman Aşımı (Timeout) Ayarlarını Anlayın
Jest’in varsayılan olarak her test için 5 saniyelik bir zaman aşımı süresi vardır. Eğer asenkron işleminiz bu süreden daha uzun sürüyorsa, Jest testi başarısız kabul eder. Bu süreyi jest.setTimeout(ms) ile global olarak veya test('...', () => {...}, ms) ile her test için ayrı ayrı ayarlayabilirsiniz.
test('this test takes a long time', async () => {
await someLongRunningAsyncOperation();
}, 10000); // Bu test için 10 saniye zaman aşımı
Anlamlı Test İsimleri Kullanın
Asenkron testler, senkron testlere göre biraz daha karmaşık olabileceğinden, test isimlerinin neyi test ettiğini ve hangi senaryoyu kapsadığını açıkça belirtmesi önemlidir. Örneğin, “should resolve with correct data” veya “should reject with a specific error message”.
Sonuç
Asenkron programlama, modern JavaScript uygulamalarının kalbinde yer alır ve bu kodları doğru bir şekilde test etmek, uygulamanın güvenilirliğini ve sürdürülebilirliğini sağlamak için kritik öneme sahiptir. Jest, Promise’ler, async/await ve done() callback’i gibi çeşitli yaklaşımlarla asenkron kodları test etmek için kapsamlı ve kullanımı kolay bir çerçeve sunar.
Bu makalede ele aldığımız gibi, async/await kullanımı en modern ve okunabilir yaklaşımdır. Jest’in .resolves ve .rejects gibi özel eşleştiricileri, Promise tabanlı testleri daha da kolaylaştırır. jest.useFakeTimers() ile zaman tabanlı asenkron işlemleri kontrol altına almak ve jest.mock() ile dış bağımlılıkları taklit etmek, testlerinizi daha hızlı, izole ve güvenilir hale getirir.
En iyi uygulamaları takip ederek – async/await‘i tercih etmek, expect.assertions(n) kullanmak, testleri izole etmek ve anlamlı test isimleri vermek – asenkron testlerinizi daha verimli bir şekilde yazabilir ve uygulamanızın kalitesini artırabilirsiniz. Jest’in sunduğu bu güçlü araçlarla, asenkron kodlarınızın beklendiği gibi çalıştığından emin olabilir, böylece daha sağlam ve hatasız uygulamalar geliştirebilirsiniz.
