Mock — test vaqtida haqiqiy dependency o‘rnini bosib, oldindan belgilangan behavior ko‘rsatadigan va u bilan qanday interaction bo‘lganini tekshirish imkonini beradigan test obyektidir. Mock odatda method chaqirildimi, qanday argument bilan chaqirildi va necha marta chaqirildi kabi savollarga javob beradi.
Mock unit testni database, network, email provider yoki boshqa tashqi tizimdan ajratishga yordam beradi.
Dependency o‘rnini bosish
Test qilinayotgan service quyidagi dependencyga ega bo‘lishi mumkin:
- repository;
- API client;
- message broker;
- clock;
- file system;
- payment gateway.
Haqiqiy dependency o‘rniga interface’ga mos mock beriladi.
Test faqat bitta unit behaviorini tekshiradi.
Behavior sozlash
Mock ma’lum chaqiriqqa kerakli natija qaytaradigan qilib sozlanadi.
Masalan:
get_user(10) → User(id=10)
Yoki exception chiqarishi mumkin:
charge() → PaymentError
Bu success va failure holatlarini boshqariladigan tarzda test qilish imkonini beradi.
Interaction verification
Mockning muhim xususiyati chaqiriqlarni yozib borishidir.
Test quyidagilarni tekshiradi:
- method chaqirildi;
- bir marta chaqirildi;
- aniq argument berildi;
- boshqa method chaqirilmadi;
- tartib saqlandi.
Bu behavior-oriented testga yaqin.
State va behavior testi
State-based test yakuniy natijani tekshiradi:
order.status == "paid"
Behavior-based test esa interactionni tekshiradi:
payment.charge(order.total) chaqirildi
Har vazifada interactionni tekshirish shart emas. Muhim observable natija bo‘lsa state testi barqarorroq.
Interface
Mock ko‘pincha aniq interface yoki protocol asosida yaratiladi.
Bu test qilinayotgan classni concrete implementationdan ajratadi.
Agar dependency global function yoki static singleton bo‘lsa mock qilish qiyinlashadi.
Dependency injection testabilityni yaxshilaydi.
Autospec
Dynamic tillarda mock mavjud bo‘lmagan methodni ham qabul qilishi mumkin.
Spec yoki autospec real class interface’ini cheklaydi.
Production method nomi o‘zgarsa test ham xato beradi.
Bu “test o‘tdi, ammo real objectda method yo‘q” muammosini kamaytiradi.
Return value
Mock method return value oladi.
Bir necha chaqiriqda turli natija berishi mumkin:
1-chaqiriq → timeout
2-chaqiriq → success
Retry logic shu tarzda test qilinadi.
Return type real dependency contractiga mos bo‘lishi kerak.
Side effect
Mock:
- exception chiqarish;
- callback chaqirish;
- argumentni o‘zgartirish;
- vaqtni simulyatsiya qilish;
- ketma-ket natija
kabi side effectga ega bo‘lishi mumkin.
Haddan tashqari murakkab mock testning o‘zini tushunishni qiyinlashtiradi.
Async mock
Asynchronous method uchun await qilinadigan mock kerak.
Test method await qilinganini tekshirishi mumkin.
Oddiy synchronous mock coroutine o‘rniga ishlatilsa runtime warning yoki noto‘g‘ri behavior yuz beradi.
Event loop va timeout nazorat qilinadi.
Partial mock
Real objectning ayrim methodlari ishlaydi, ayrimlari almashtiriladi.
Bu ba’zan legacy code uchun kerak.
Biroq objectning ichki implementationiga kuchli bog‘lanish yaratadi.
Refactoringdan keyin testlar ko‘p buzilishi mumkin.
Spy bilan farqi
Spy odatda haqiqiy object yoki methodni chaqirishni davom ettirib, interactionni yozadi.
Mock esa behaviorni to‘liq almashtirishi mumkin.
Framework terminlari farq qilishi ehtimoli bor.
Muhim narsa test double qanday ishlayotganini aniq bilishdir.
Stub bilan farqi
Stub oldindan natija qaytaradi, interactionni tekshirish asosiy maqsad emas.
Mock esa expectation va verificationga urg‘u beradi.
Amaliy frameworklarda bitta obyekt stub va mock vazifasini birga bajarishi mumkin.
Over-mocking
Har class va har methodni mock qilish testni implementation detailga bog‘laydi.
Masalan, ichki helper ikki marta chaqirilganini tekshirish business behavior uchun muhim bo‘lmasligi mumkin.
Refactoring behaviorni o‘zgartirmasa ham testlar yiqiladi.
Faqat boundary va qimmat dependencylar mock qilinadi.
False confidence
Mock real service contractini noto‘g‘ri takrorlashi mumkin.
Test o‘tadi, production integration esa ishlamaydi.
Masalan, mock API fieldni string qaytaradi, haqiqiy API null berishi mumkin.
Contract test va integration test bu xavfni kamaytiradi.
Database mock
ORM yoki query builderni chuqur mock qilish ko‘pincha murakkab.
In-memory yoki test database real query behaviorini yaxshiroq tekshirishi mumkin.
Repository boundary mock qilinsa unit test sodda qoladi.
SQL syntax mock bilan tekshirilmaydi.
Time mock
Clock dependency sifatida berilsa test aniq vaqtni nazorat qiladi.
Bu:
- expiration;
- schedule;
- retry;
- date boundary;
- timezone
testlarida foydali.
Global system vaqtini o‘zgartirish parallel testlarga ta’sir qilishi mumkin.
HTTP mock
API clientga fake response beriladi.
Status, header, body va timeout ssenariylari tekshiriladi.
Faqat application clientini mock qilish serialization va haqiqiy HTTP stackni test qilmaydi.
Mock server integration testda kuchliroq signal beradi.
Verification qoidasi
Expectation juda qattiq bo‘lmasligi kerak.
Argumentning faqat muhim qismi tekshiriladi.
Masalan, generated request ID har run boshqa bo‘lsa exact object tengligi noto‘g‘ri.
Matcher va predicate ishlatiladi.
Test readability
Mock setup testning “berilgan” qismida aniq ko‘rinadi.
Interaction assertion testning “tekshirish” qismida joylashadi.
Bir testda o‘nlab mock va expectation bo‘lsa unit juda ko‘p javobgarlikka ega bo‘lishi mumkin.
Strict va loose mock
Strict mock oldindan belgilanmagan chaqiriqda darhol xato beradi. Loose mock esa default qiymat qaytarishi mumkin. Strict usul kutilmagan interactionni topadi, lekin refactoringga sezgir. Loose usul sodda, ammo muhim chaqiriq unutilganini yashirishi mumkin.
Argument capture
Mockka berilgan murakkab obyekt capture qilinib, keyin uning muhim fieldlari alohida tekshiriladi. Bu butun obyektni exact equality bilan solishtirishdan ko‘ra tushunarli bo‘lishi mumkin.
Bog‘liq tushunchalar
Mock object, Test double, Stub, Spy, Fake, Dependency injection, Unit testing, Interaction testing, Autospec, Contract testing