Async testlar va mock
Real dasturlar tarmoq so'rovlari, ma'lumotlar bazasi va tashqi xizmatlar bilan ishlaydi. Bularni testda to'g'ri tekshirish uchun asinxron testlar va mock (soxta) obyektlarni bilish shart. Bu darsda aynan shularni o'rganamiz.
Asinxron kodni testlash muammosi
Agar test ichida promise bo'lsa, lekin siz uni kutmasangiz, Jest testni tugadi deb hisoblaydi va natija kelishidan oldin yashil ko'rsatadi. Bu xavfli โ test aslida hech narsani tekshirmagan bo'lishi mumkin:
// XATO: bu test har doim o'tadi, hatto natija noto'g'ri bo'lsa ham!
test('foydalanuvchini oladi', () => {
foydalanuvchiOl(1).then(user => {
expect(user.ism).toBe('Ali'); // Jest buni kutmaydi
});
});
return qilishni yoki async/await ishlatishni unutmang. Aks holda Jest natijani kutmasdan testni tugatadi va soxta yashil natija chiqadi.async/await bilan testlash
Eng toza yo'l โ test funksiyasini async qilish va promise'ni await bilan kutish:
async function foydalanuvchiOl(id) {
// aslida bu yerda tarmoq so'rovi bo'ladi
return { id, ism: 'Ali' };
}
test('foydalanuvchini id bo'yicha oladi', async () => {
const user = await foydalanuvchiOl(1);
expect(user.ism).toBe('Ali');
expect(user.id).toBe(1);
});
Bu yerda await promise hal bo'lishini kutadi, so'ng tekshiruvlar bajariladi. Jest async funksiya qaytargan promise'ni avtomatik kutadi.
resolves va rejects
Promise'ni awaitsiz to'g'ridan-to'g'ri tekshirishning qisqa yo'li ham bor: resolves muvaffaqiyatli natijani, rejects esa xatoni tekshiradi:
// Promise muvaffaqiyatli hal bo'lishini tekshirish:
test('foydalanuvchi obyektini qaytaradi', async () => {
await expect(foydalanuvchiOl(1)).resolves.toEqual({ id: 1, ism: 'Ali' });
});
// Promise xato bilan rad etilishini tekshirish:
async function xatoOl() {
throw new Error('Topilmadi');
}
test('mavjud bo'lmagan foydalanuvchi uchun xato beradi', async () => {
await expect(xatoOl()).rejects.toThrow('Topilmadi');
});
resolves va rejects oldida await qo'yishni unutmang. Bularsiz Jest promise natijasini kutmaydi.Mock funksiya: jest.fn()
Mock (soxta) funksiya โ bu chaqiruvlarni yozib boradigan va siz belgilagan qiymatni qaytaradigan sun'iy funksiya. U jest.fn() bilan yaratiladi. Mocklar ikki holatda juda foydali:
- Funksiya chaqirilganini, necha marta va qanday argument bilan chaqirilganini tekshirish.
- Real, sekin yoki xavfli kodni (masalan tarmoq so'rovi) sinovda soxta versiya bilan almashtirish.
test('mock funksiya chaqiruvlarni yozadi', () => {
const mock = jest.fn();
mock('a');
mock('b', 42);
// Chaqirilganini tekshirish:
expect(mock).toHaveBeenCalled();
expect(mock).toHaveBeenCalledTimes(2);
expect(mock).toHaveBeenCalledWith('a');
expect(mock).toHaveBeenCalledWith('b', 42);
});
Mock qanday qiymat qaytarishini ham belgilash mumkin:
const olMock = jest.fn();
olMock.mockReturnValue(10); // har safar 10 qaytaradi
olMock.mockReturnValueOnce(5); // faqat birinchi chaqiruvda 5
olMock.mockResolvedValue({ ok: 1 }); // promise sifatida hal bo'ladi
expect(olMock()).toBe(5); // birinchisi
expect(olMock()).toBe(10); // keyingilari
Modulni mock qilish: jest.mock()
Ko'pincha butun modulni soxtalashtirish kerak bo'ladi โ masalan, testda real tarmoq so'rovi yubormaslik uchun HTTP kutubxonasini almashtiramiz. Buni jest.mock() qiladi. Aytaylik, bizda foydalanuvchini serverdan oladigan xizmat bor:
// apiClient.js
async function get(url) {
// aslida real tarmoq so'rovi
const javob = await fetch(url);
return javob.json();
}
module.exports = { get };
// foydalanuvchiXizmati.js
const apiClient = require('./apiClient');
async function foydalanuvchiIsmi(id) {
const user = await apiClient.get('/users/' + id);
return user.ism;
}
module.exports = { foydalanuvchiIsmi };
Testda apiClient modulini butunlay mock qilamiz, shunda real tarmoqqa chiqmaydi:
// foydalanuvchiXizmati.test.js
const apiClient = require('./apiClient');
const { foydalanuvchiIsmi } = require('./foydalanuvchiXizmati');
jest.mock('./apiClient'); // butun modul avtomatik mock bo'ladi
test('foydalanuvchi ismini qaytaradi', async () => {
// get soxta funksiyasi nima qaytarishini belgilaymiz:
apiClient.get.mockResolvedValue({ ism: 'Vali' });
const ism = await foydalanuvchiIsmi(7);
expect(ism).toBe('Vali');
expect(apiClient.get).toHaveBeenCalledWith('/users/7');
});
jest.mock('./apiClient') chaqirilganda Jest moduldagi barcha funksiyalarni avtomatik jest.fn()ga aylantiradi. So'ng test ichida har biriga qaytariladigan qiymatni bering.beforeEach va afterEach
Har bir testdan oldin yoki keyin bir xil tayyorgarlik yoki tozalash kerak bo'ladi. Buning uchun hooklar ishlatiladi:
beforeEachโ har bir testdan oldin ishlaydi (masalan ma'lumotni tayyorlash).afterEachโ har bir testdan keyin ishlaydi (masalan mocklarni tozalash).beforeAll/afterAllโ butun fayl bo'yicha faqat bir marta ishlaydi.
describe('savat', () => {
let savat;
beforeEach(() => {
// har bir testdan oldin toza savat yaratamiz
savat = [];
});
afterEach(() => {
// mock chaqiruvlar tarixini tozalaymiz
jest.clearAllMocks();
});
test('mahsulot qo'shadi', () => {
savat.push('olma');
expect(savat).toHaveLength(1);
});
test('yangi test toza savatdan boshlanadi', () => {
expect(savat).toHaveLength(0); // beforeEach uni tozaladi
});
});
afterEachda jest.clearAllMocks() chaqirish โ yaxshi odat.Spy โ haqiqiy funksiyani kuzatish
Ba'zan funksiyani butunlay almashtirmasdan, faqat kuzatmoqchi bo'lasiz: u chaqirildimi, qanday argument bilan? Bunda jest.spyOn ishlatiladi. Spy asl funksiyani saqlab qoladi, lekin chaqiruvlarni yozib boradi:
const kalkulyator = {
qoshish(a, b) {
return a + b;
}
};
test('qoshish metodi chaqirilganini kuzatadi', () => {
const spy = jest.spyOn(kalkulyator, 'qoshish');
const natija = kalkulyator.qoshish(2, 3);
expect(natija).toBe(5); // asl funksiya baribir ishladi
expect(spy).toHaveBeenCalledWith(2, 3);
spy.mockRestore(); // asl holatga qaytaramiz
});
mockRestore() bilan tiklashni unutmang, aks holda kuzatuv keyingi testlarga ta'sir qiladi. Kerak bo'lsa spy'ni mockImplementation() bilan vaqtincha boshqacha ishlashga majburlash ham mumkin.Xulosa
- Asinxron testda promise'ni
async/awaitbilan kuting yokireturnqiling โ aks holda soxta yashil natija chiqadi. resolvesmuvaffaqiyatli natijani,rejectsxatoni tekshiradi (oldidaawaitbilan).jest.fn()โ mock funksiya; chaqiruvlarni yozadi va qiymat qaytaradi.jest.mock('./modul')butun modulni mockga aylantiradi โ real tarmoqqa chiqmaslik uchun.beforeEach/afterEachhar test uchun tayyorlash va tozalash bajaradi; mocklarniclearAllMocksbilan tozalang.jest.spyOnasl funksiyani saqlab, faqat chaqiruvlarni kuzatadi; oxiridamockRestore()qiling.