Mustahkam va ishonchli dasturiy ta'minot yaratish uchun testlash strategiyangizda mock funksiyalardan samarali foydalanishni o'rganing. Bu qo'llanma amaliy misollar bilan mocklarni qachon, nima uchun va qanday qo'llashni qamrab oladi.
Mock Funksiyalar: Dasturchilar uchun Toʻliq Qoʻllanma
Dasturiy ta'minotni ishlab chiqish olamida mustahkam va ishonchli kod yozish eng muhim vazifadir. Bunga erishish uchun puxta testlash hal qiluvchi ahamiyatga ega. Xususan, unit testlash alohida komponentlar yoki funksiyalarni izolyatsiyalangan holda sinab ko'rishga qaratilgan. Biroq, real hayotdagi ilovalar ko'pincha murakkab bog'liqliklarni o'z ichiga oladi, bu esa birliklarni to'liq izolyatsiyada sinab ko'rishni qiyinlashtiradi. Aynan shu yerda mock funksiyalar yordamga keladi.
Mock Funksiyalar nima?
Mock funksiya – bu testlaringizda foydalanishingiz mumkin bo'lgan haqiqiy funksiyaning simulyatsiya qilingan versiyasidir. Haqiqiy funksiya mantiqini bajarish o'rniga, mock funksiya uning xatti-harakatini boshqarish, u qanday chaqirilayotganini kuzatish va qaytariladigan qiymatlarini belgilash imkonini beradi. Ular test dublyori (test double) turidir.
Buni quyidagicha tasavvur qiling: siz avtomobil dvigatelini (test qilinayotgan birlik) sinayapsiz. Dvigatel yoqilg'i quyish tizimi va sovutish tizimi kabi turli xil boshqa komponentlarga tayanadi. Dvigatelni sinash paytida haqiqiy yoqilg'i quyish va sovutish tizimlarini ishlatish o'rniga, ularning xatti-harakatlarini simulyatsiya qiluvchi soxta tizimlardan foydalanishingiz mumkin. Bu sizga dvigatelni izolyatsiya qilish va uning ishlashiga alohida e'tibor qaratish imkonini beradi.
Mock funksiyalar quyidagilar uchun kuchli vositalardir:
- Birliklarni izolyatsiya qilish: Yagona funksiya yoki komponentning xatti-harakatiga e'tibor qaratish uchun tashqi bog'liqliklarni olib tashlash.
- Xatti-harakatni boshqarish: Maxsus qaytariladigan qiymatlarni belgilash, xatoliklarni yuzaga keltirish yoki testlash paytida maxsus mantiqni bajarish.
- O'zaro ta'sirlarni kuzatish: Funksiya necha marta chaqirilganini, qanday argumentlar qabul qilganini va qaysi tartibda chaqirilganini kuzatish.
- Noyob holatlarni simulyatsiya qilish: Haqiqiy muhitda qayta yaratish qiyin yoki imkonsiz bo'lgan stsenariylarni (masalan, tarmoq uzilishlari, ma'lumotlar bazasi xatolari) osonlik bilan yaratish.
Mock Funksiyalardan qachon foydalanish kerak
Mocks quyidagi holatlarda eng foydalidir:1. Tashqi bog'liqliklarga ega birliklarni izolyatsiya qilish
Siz test qilayotgan birlik tashqi xizmatlar, ma'lumotlar bazalari, APIlar yoki boshqa komponentlarga bog'liq bo'lsa, testlash paytida haqiqiy bog'liqliklardan foydalanish bir nechta muammolarni keltirib chiqarishi mumkin:
- Sekin testlar: Haqiqiy bog'liqliklarni sozlash va bajarish sekin bo'lishi mumkin, bu esa testning bajarilish vaqtini sezilarli darajada oshiradi.
- Ishonchsiz testlar: Tashqi bog'liqliklar oldindan aytib bo'lmaydigan va nosozliklarga moyil bo'lishi mumkin, bu esa beqaror testlarga olib keladi.
- Murakkablik: Haqiqiy bog'liqliklarni boshqarish va sozlash sizning test sozlamalaringizga keraksiz murakkablik qo'shishi mumkin.
- Xarajat: Tashqi xizmatlardan foydalanish ko'pincha xarajatlarga olib keladi, ayniqsa keng ko'lamli testlash uchun.
Misol: Siz masofaviy API'dan foydalanuvchi ma'lumotlarini oladigan funksiyani sinayapsiz deb tasavvur qiling. Testlash paytida haqiqiy API so'rovlarini amalga oshirish o'rniga, API javobini simulyatsiya qilish uchun mock funksiyadan foydalanishingiz mumkin. Bu sizga funksiya mantiqini tashqi API'ning mavjudligi yoki ishlashiga tayanmasdan sinab ko'rish imkonini beradi. Bu ayniqsa API'da har bir so'rov uchun so'rovlar chegarasi yoki xarajatlar mavjud bo'lganda muhimdir.
2. Murakkab o'zaro ta'sirlarni sinab ko'rish
Ba'zi hollarda, siz test qilayotgan birlik boshqa komponentlar bilan murakkab usullarda o'zaro ta'sir qilishi mumkin. Mock funksiyalar ushbu o'zaro ta'sirlarni kuzatish va tekshirish imkonini beradi.
Misol: To'lov operatsiyalarini qayta ishlaydigan funksiyani ko'rib chiqing. Bu funksiya to'lov shlyuzi, ma'lumotlar bazasi va bildirishnoma xizmati bilan o'zaro ta'sir qilishi mumkin. Mock funksiyalardan foydalanib, siz funksiya to'lov shlyuzini to'g'ri tranzaksiya tafsilotlari bilan chaqirganligini, ma'lumotlar bazasini tranzaksiya holati bilan yangilaganligini va foydalanuvchiga bildirishnoma yuborganligini tekshirishingiz mumkin.
3. Xatolik holatlarini simulyatsiya qilish
Xatoliklarni qayta ishlashni sinab ko'rish dasturingizning mustahkamligini ta'minlash uchun juda muhimdir. Mock funksiyalar haqiqiy muhitda qayta yaratish qiyin yoki imkonsiz bo'lgan xatolik holatlarini simulyatsiya qilishni osonlashtiradi.
Misol: Aytaylik, siz fayllarni bulutli saqlash xizmatiga yuklaydigan funksiyani sinayapsiz. Siz yuklash jarayonida tarmoq xatosini simulyatsiya qilish uchun mock funksiyadan foydalanishingiz mumkin. Bu sizga funksiya xatolikni to'g'ri boshqarishini, yuklashni qayta urinishini yoki foydalanuvchiga xabar berishini tekshirish imkonini beradi.
4. Asinxron kodni sinab ko'rish
Asinxron kod, masalan, callbacks, promises yoki async/await dan foydalanadigan kodni sinab ko'rish qiyin bo'lishi mumkin. Mock funksiyalar asinxron operatsiyalarning vaqtini va xatti-harakatini boshqarishga yordam beradi.
Misol: Tasavvur qiling, siz asinxron so'rov yordamida serverdan ma'lumotlarni oladigan funksiyani sinayapsiz. Siz server javobini simulyatsiya qilish va javob qachon qaytarilishini boshqarish uchun mock funksiyadan foydalanishingiz mumkin. Bu sizga funksiyaning turli javob stsenariylari va taym-autlarni qanday boshqarishini sinab ko'rish imkonini beradi.
5. Kutilmagan qo'shimcha ta'sirlarning oldini olish
Ba'zida, testlash paytida haqiqiy funksiyani chaqirish kutilmagan qo'shimcha ta'sirlarga olib kelishi mumkin, masalan, ma'lumotlar bazasini o'zgartirish, elektron pochta xabarlarini yuborish yoki tashqi jarayonlarni ishga tushirish. Mock funksiyalar haqiqiy funksiyani boshqariladigan simulyatsiya bilan almashtirish orqali bu qo'shimcha ta'sirlarning oldini oladi.
Misol: Siz yangi foydalanuvchilarga xush kelibsiz xabarlarini yuboradigan funksiyani sinayapsiz. Soxta elektron pochta xizmatidan foydalanib, siz test to'plamingiz ishlashi paytida elektron pochta yuborish funksiyasi haqiqiy foydalanuvchilarga xabar yubormasligini ta'minlashingiz mumkin. Buning o'rniga, funksiya to'g'ri ma'lumotlar bilan elektron pochta yuborishga harakat qilganligini tekshirishingiz mumkin.
Mock Funksiyalardan qanday foydalanish kerak
Mock funksiyalardan foydalanishning aniq qadamlari siz foydalanayotgan dasturlash tili va testlash freymvorkiga bog'liq. Biroq, umumiy jarayon odatda quyidagi bosqichlarni o'z ichiga oladi:
- Bog'liqliklarni aniqlash: Qaysi tashqi bog'liqliklarni soxtalashtirish kerakligini aniqlang.
- Mock ob'ektlarini yaratish: Haqiqiy bog'liqliklarni almashtirish uchun mock ob'ektlari yoki funksiyalarini yarating. Bu mocklar ko'pincha `called`, `returnValue` va `callArguments` kabi xususiyatlarga ega bo'ladi.
- Mock xatti-harakatini sozlash: Mock funksiyalarining xatti-harakatini, masalan, ularning qaytariladigan qiymatlarini, xatolik holatlarini va chaqiruvlar sonini belgilang.
- Mocklarni kiritish: Haqiqiy bog'liqliklarni test qilinayotgan birligingizdagi mock ob'ektlari bilan almashtiring. Bu ko'pincha bog'liqliklarni kiritish (dependency injection) yordamida amalga oshiriladi.
- Testni bajarish: Testni ishga tushiring va test qilinayotgan birlikning mock funksiyalar bilan qanday o'zaro ta'sir qilishini kuzating.
- O'zaro ta'sirlarni tekshirish: Mock funksiyalar kutilgan argumentlar, qaytariladigan qiymatlar va chaqiruvlar soni bilan chaqirilganligini tekshiring.
- Asl funksionallikni tiklash: Testdan so'ng, mock ob'ektlarini olib tashlash va haqiqiy bog'liqliklarga qaytish orqali asl funksionallikni tiklang. Bu boshqa testlarga qo'shimcha ta'sirlarni oldini olishga yordam beradi.
Turli tillarda Mock Funksiya misollari
Quyida mashhur dasturlash tillari va testlash freymvorklarida mock funksiyalardan foydalanish misollari keltirilgan:JavaScript va Jest
Jest - bu mock funksiyalarni o'rnatilgan holda qo'llab-quvvatlaydigan mashhur JavaScript testlash freymvorkidir.
// Test qilinadigan funksiya
function fetchData(callback) {
setTimeout(() => {
callback('Serverdan ma\'lumotlar');
}, 100);
}
// Test holati
test('fetchData callbackni to\'g\'ri ma\'lumot bilan chaqiradi', (done) => {
const mockCallback = jest.fn();
fetchData(mockCallback);
setTimeout(() => {
expect(mockCallback).toHaveBeenCalledWith('Serverdan ma\'lumotlar');
done();
}, 200);
});
Ushbu misolda `jest.fn()` haqiqiy callback funksiyasini almashtiradigan mock funksiya yaratadi. Test `toHaveBeenCalledWith()` yordamida mock funksiyaning to'g'ri ma'lumotlar bilan chaqirilganligini tekshiradi.
Modullar yordamida yanada rivojlangan misol:
// user.js
import { getUserDataFromAPI } from './api';
export async function displayUserName(userId) {
const userData = await getUserDataFromAPI(userId);
return userData.name;
}
// api.js
export async function getUserDataFromAPI(userId) {
// API so'rovini simulyatsiya qilish
return new Promise(resolve => {
setTimeout(() => {
resolve({ id: userId, name: 'John Doe' });
}, 50);
});
}
// user.test.js
import { displayUserName } from './user';
import * as api from './api';
describe('displayUserName', () => {
it('foydalanuvchi nomini ko\'rsatishi kerak', async () => {
// getUserDataFromAPI funksiyasini soxtalashtirish
const mockGetUserData = jest.spyOn(api, 'getUserDataFromAPI');
mockGetUserData.mockResolvedValue({ id: 123, name: 'Mocked Name' });
const userName = await displayUserName(123);
expect(userName).toBe('Mocked Name');
// Asl funksiyani tiklash
mockGetUserData.mockRestore();
});
});
Bu yerda `jest.spyOn` `./api` modulidan import qilingan `getUserDataFromAPI` funksiyasi uchun mock funksiya yaratish uchun ishlatiladi. `mockResolvedValue` mockning qaytariladigan qiymatini belgilash uchun ishlatiladi. `mockRestore` boshqa testlarning tasodifan soxtalashtirilgan versiyani ishlatmasligini ta'minlash uchun muhimdir.
Python, pytest va unittest.mock bilan
Python mock uchun bir nechta kutubxonalarni taklif qiladi, jumladan `unittest.mock` (o'rnatilgan) va pytest bilan soddalashtirilgan foydalanish uchun `pytest-mock` kabi kutubxonalar.
# Test qilinadigan funksiya
def get_data_from_api(url):
# Haqiqiy stsenariyda bu API so'rovini amalga oshiradi
# Soddalik uchun API so'rovini simulyatsiya qilamiz
if url == "https://example.com/api":
return {"data": "API data"}
else:
return None
def process_data(url):
data = get_data_from_api(url)
if data:
return data["data"]
else:
return "No data found"
# unittest.mock yordamida test holati
import unittest
from unittest.mock import patch
class TestProcessData(unittest.TestCase):
@patch('__main__.get_data_from_api') # Asosiy moduldagi get_data_from_api ni almashtirish
def test_process_data_success(self, mock_get_data_from_api):
# Mockni sozlash
mock_get_data_from_api.return_value = {"data": "Mocked data"}
# Test qilinayotgan funksiyani chaqirish
result = process_data("https://example.com/api")
# Natijani tekshirish
self.assertEqual(result, "Mocked data")
mock_get_data_from_api.assert_called_once_with("https://example.com/api")
@patch('__main__.get_data_from_api')
def test_process_data_failure(self, mock_get_data_from_api):
mock_get_data_from_api.return_value = None
result = process_data("https://example.com/api")
self.assertEqual(result, "No data found")
if __name__ == '__main__':
unittest.main()
Ushbu misol `get_data_from_api` funksiyasini mock bilan almashtirish uchun `unittest.mock.patch` dan foydalanadi. Test mockni ma'lum bir qiymatni qaytarish uchun sozlaydi va keyin `process_data` funksiyasi kutilgan natijani qaytarishini tekshiradi.
Xuddi shu misol `pytest-mock` yordamida:
# pytest versiyasi
import pytest
def get_data_from_api(url):
# Haqiqiy stsenariyda bu API so'rovini amalga oshiradi
# Soddalik uchun API so'rovini simulyatsiya qilamiz
if url == "https://example.com/api":
return {"data": "API data"}
else:
return None
def process_data(url):
data = get_data_from_api(url)
if data:
return data["data"]
else:
return "No data found"
def test_process_data_success(mocker):
mocker.patch('__main__.get_data_from_api', return_value={"data": "Mocked data"})
result = process_data("https://example.com/api")
assert result == "Mocked data"
def test_process_data_failure(mocker):
mocker.patch('__main__.get_data_from_api', return_value=None)
result = process_data("https://example.com/api")
assert result == "No data found"
`pytest-mock` kutubxonasi pytest testlari ichida mocklarni yaratish va sozlashni soddalashtiradigan `mocker` fiksaturasini taqdim etadi.
Java va Mockito
Mockito - Java uchun mashhur mock freymvorkidir.
import org.junit.jupiter.api.Test;
import static org.mockito.Mockito.*;
import static org.junit.jupiter.api.Assertions.*;
interface DataFetcher {
String fetchData(String url);
}
class DataProcessor {
private final DataFetcher dataFetcher;
public DataProcessor(DataFetcher dataFetcher) {
this.dataFetcher = dataFetcher;
}
public String processData(String url) {
String data = dataFetcher.fetchData(url);
if (data != null) {
return "Processed: " + data;
} else {
return "No data";
}
}
}
public class DataProcessorTest {
@Test
public void testProcessDataSuccess() {
// Soxta DataFetcher yaratish
DataFetcher mockDataFetcher = mock(DataFetcher.class);
// Mockni sozlash
when(mockDataFetcher.fetchData("https://example.com/api")).thenReturn("API Data");
// DataProcessor ni mock bilan yaratish
DataProcessor dataProcessor = new DataProcessor(mockDataFetcher);
// Test qilinayotgan funksiyani chaqirish
String result = dataProcessor.processData("https://example.com/api");
// Natijani tasdiqlash
assertEquals("Processed: API Data", result);
// Mock chaqirilganligini tekshirish
verify(mockDataFetcher).fetchData("https://example.com/api");
}
@Test
public void testProcessDataFailure() {
DataFetcher mockDataFetcher = mock(DataFetcher.class);
when(mockDataFetcher.fetchData("https://example.com/api")).thenReturn(null);
DataProcessor dataProcessor = new DataProcessor(mockDataFetcher);
String result = dataProcessor.processData("https://example.com/api");
assertEquals("No data", result);
verify(mockDataFetcher).fetchData("https://example.com/api");
}
}
Ushbu misolda `Mockito.mock()` `DataFetcher` interfeysi uchun mock ob'ektini yaratadi. `when()` mockning qaytariladigan qiymatini sozlash uchun, `verify()` esa mockning kutilgan argumentlar bilan chaqirilganligini tekshirish uchun ishlatiladi.
Mock Funksiyalardan foydalanishning eng yaxshi amaliyotlari
- Tejamkorlik bilan soxtalashtiring: Faqat haqiqatan ham tashqi bo'lgan yoki sezilarli murakkablik keltirib chiqaradigan bog'liqliklarni soxtalashtiring. Amalga oshirish tafsilotlarini soxtalashtirishdan saqlaning.
- Mocklarni oddiy saqlang: Testlaringizga xatoliklar kiritmaslik uchun mock funksiyalar iloji boricha sodda bo'lishi kerak.
- Bog'liqliklarni kiritishdan foydalaning: Haqiqiy bog'liqliklarni mock ob'ektlari bilan almashtirishni osonlashtirish uchun bog'liqliklarni kiritishdan foydalaning. Konstruktor orqali kiritish afzalroq, chunki u bog'liqliklarni aniq ko'rsatadi.
- O'zaro ta'sirlarni tekshiring: Har doim test qilinayotgan birlikning mock funksiyalar bilan kutilgan tarzda o'zaro ta'sir qilishini tekshiring.
- Asl funksionallikni tiklang: Har bir testdan so'ng, mock ob'ektlarini olib tashlash va haqiqiy bog'liqliklarga qaytish orqali asl funksionallikni tiklang.
- Mocklarni hujjatlashtiring: Mock funksiyalaringizning maqsadi va xatti-harakatini tushuntirish uchun ularni aniq hujjatlashtiring.
- Haddan tashqari aniqlikdan saqlaning: Har bir o'zaro ta'sirni tekshirmang, siz sinayotgan xatti-harakat uchun muhim bo'lgan asosiy o'zaro ta'sirlarga e'tibor qarating.
- Integratsiya testlarini ko'rib chiqing: Mocklar bilan unit testlar muhim bo'lsa-da, ularni haqiqiy komponentlar o'rtasidagi o'zaro ta'sirlarni tekshiradigan integratsiya testlari bilan to'ldirishni unutmang.
Mock Funksiyalarga alternativlar
Mock funksiyalar kuchli vosita bo'lsa-da, ular har doim ham eng yaxshi yechim emas. Ba'zi hollarda, boshqa usullar yanada mos kelishi mumkin:
- Stablar (Stubs): Stablar mocklardan oddiyroq. Ular funksiya chaqiruvlariga oldindan belgilangan javoblarni taqdim etadilar, lekin odatda bu chaqiruvlar qanday amalga oshirilganini tekshirmaydilar. Ular faqat test qilinayotgan birligingizga kiritiladigan ma'lumotlarni nazorat qilish kerak bo'lganda foydalidir.
- Shpionlar (Spies): Shpionlar haqiqiy funksiyaning asl mantiqini bajarishiga imkon bergan holda uning xatti-harakatini kuzatish imkonini beradi. Ular funksiyaning ma'lum argumentlar bilan yoki ma'lum bir necha marta chaqirilganligini, uning funksionalligini to'liq almashtirmasdan tekshirishni xohlaganingizda foydalidir.
- Fakes: Fakes bog'liqlikning ishlaydigan, lekin testlash maqsadlari uchun soddalashtirilgan implementatsiyasidir. Xotiradagi ma'lumotlar bazasi (in-memory database) fake'ga misol bo'la oladi.
- Integratsiya testlari: Integratsiya testlari bir nechta komponentlar o'rtasidagi o'zaro ta'sirlarni tekshiradi. Ular tizimning yaxlit xatti-harakatini sinab ko'rishni xohlaganingizda mocklar bilan unit testlarga yaxshi alternativa bo'lishi mumkin.
Xulosa
Mock funksiyalar samarali unit testlarni yozish, birliklarni izolyatsiya qilish, xatti-harakatni nazorat qilish, xatolik holatlarini simulyatsiya qilish va asinxron kodni sinab ko'rish imkonini beruvchi muhim vositadir. Eng yaxshi amaliyotlarga rioya qilish va alternativlarni tushunish orqali siz yanada mustahkam, ishonchli va qo'llab-quvvatlanadigan dasturiy ta'minot yaratish uchun mock funksiyalardan unumli foydalanishingiz mumkin. Dunyoning qaysi burchagida ish olib borishingizdan qat'i nazar, har bir vaziyat uchun to'g'ri testlash usulini tanlash va keng qamrovli va samarali testlash strategiyasini yaratish uchun afzallik va kamchiliklarni hisobga olishni unutmang.