Object Mother — testlarda kerakli obyektlarni tayyor holatda yaratib beradigan yordamchi pattern. U murakkab fixture, ko‘p constructor argumenti va takroriy test setup kodini markazlashtiradi.
Object Mother production design pattern emas, asosan test code’ni o‘qilishi va qayta ishlatilishini yaxshilash uchun ishlatiladi.
Muammo
Har testda quyidagicha obyekt yaratish takrorlanishi mumkin:
user = User(
name="Farrukh",
email="[email protected]",
role="member",
active=True,
verified=True,
country="UZ",
)
O‘nlab field va bog‘liq obyektlar bo‘lsa testning asosiy maqsadi setup ichida yo‘qoladi.
Asosiy g‘oya
Object Mother ma’noli nomlangan factory methodlar beradi.
Masalan:
UserMother.active_user()
UserMother.admin()
UserMother.unverified_user()
Test kerakli scenario obyektini bir qatorda oladi.
Method nomi obyektning muhim holatini tushuntiradi.
Default valid object
Eng ko‘p ishlatiladigan method to‘liq valid obyekt qaytaradi.
Masalan:
user = UserMother.valid_user()
Default qiymatlar test uchun barqaror va tushunarli bo‘ladi.
Random qiymatlar test natijasini takrorlashni qiyinlashtirmasligi kerak.
Scenario method
Domain holatlari uchun alohida methodlar yaratiladi.
Misollar:
paid_order();expired_subscription();blocked_user();empty_cart();failed_payment().
Bu testni business tiliga yaqinlashtiradi.
Override
Test default obyektning faqat bitta fieldini o‘zgartirishni xohlashi mumkin.
Object Mother keyword override qabul qilishi mumkin:
user = UserMother.active_user(country="KZ")
Override methodlar sonini haddan tashqari ko‘paytirishni kamaytiradi.
Nested object
Murakkab aggregate ichida boshqa mother yoki builder ishlatiladi.
Masalan, order:
customer
items
address
payment
status
OrderMother default customer va itemlarni yaratadi.
Test faqat muhim dependency’ni almashtiradi.
Object Mother va Test Data Builder
Object Mother tayyor nomlangan scenario obyektlarini qaytaradi.
Test Data Builder esa fieldlarni fluent qadamlar bilan boshqaradi.
Masalan:
UserBuilder
.active()
.with_country("UZ")
.build()
Ikkalasi birga ishlatilishi mumkin.
Mother ichida builderdan foydalanadi.
Object Mother va Factory
Oddiy factory generic obyekt yaratadi.
Object Mother test scenario va semantik holatlarga yo‘naltirilgan.
Production factory business lifecycle’ga ta’sir qilishi mumkin.
Object Mother faqat test isolation uchun.
Deterministik qiymat
Test data odatda deterministic bo‘ladi.
Masalan:
- fixed timestamp;
- stable ID;
- aniq email;
- aniq amount.
Current time yoki global randomga tayanish flaky test yaratishi mumkin.
Random data kerak bo‘lsa seed qayd etiladi.
Unique qiymat
Database integration testlarida unique constraint sabab har obyektga noyob email yoki ID kerak bo‘lishi mumkin.
Counter, test UUID yoki test nomidan key yaratiladi.
Global counter parallel testlarda thread-safe bo‘lishi kerak.
Validatsiya bilan bog‘liqlik
Object Mother production constructor va invariantlardan foydalanadi.
Schema o‘zgarsa mother compile yoki testda tez buziladi.
Bu test fixture’larini yangilash uchun bitta markaziy joy beradi.
Ammo defaultlar real business holatni yashirmasligi kerak.
Invalid object
Ba’zi testlar invalid obyekt talab qiladi.
Agar production constructor invalid holat yaratishga yo‘l qo‘ymasa, DTO, raw input yoki mock ishlatiladi.
Invariantni buzish uchun private fieldni yashirin o‘zgartirish testni implementationga qattiq bog‘laydi.
Persistence
Object Mother obyektni faqat memory’da yaratishi yoki database’ga saqlashi mumkin.
Bu ikki vazifa ajratilgani yaxshi:
build_user()
persist_user()
Aks holda oddiy unit test tasodifan database’ga bog‘lanadi.
Fixture explosion
Har kichik kombinatsiya uchun yangi method yaratilsa Object Mother juda katta bo‘lib ketadi.
Masalan:
active_verified_admin_from_uz_with_two_orders
Bu kombinator explosion.
Yechim:
Hidden defaults
Test active_user() oladi, ammo uning ichida qaysi role, timezone yoki permission borligini bilmasligi mumkin.
Test natijasi hidden defaultga tasodifan bog‘lanadi.
Muhim fieldlar testning o‘zida explicit ko‘rsatiladi.
Shared mutable object
Mother bir xil mutable instance’ni barcha testlarga qaytarmasligi kerak.
Bir test obyektni o‘zgartirsa boshqasiga ta’sir qiladi.
Har chaqiriqda yangi obyekt yoki deep copy yaratiladi.
Test readability
Yaxshi test:
given expired subscription
when renewal attempted
then payment required
Object Mother expired_subscription() bilan given qismini aniq qiladi.
Fixture yaratish detali testning behavior maqsadini bosib ketmaydi.
Maintenance
Object Mother domain moduliga yaqin joylashtiriladi.
Masalan:
tests/mothers/user_mother.py
Bitta ulkan global mother barcha modullarni bog‘lamaydi.
Har aggregate uchun alohida helper saqlanadi.
Domain tiliga mos nom
Mother methodlari texnik fieldlar emas, test ssenariysini ifodalashi kerak.
user_with_active_true() o‘rniga eligible_customer() aniqroq bo‘lishi mumkin, agar test aynan xaridga ruxsat holatini tekshirsa.
Nom business ma’noni yashirmasligi kerak.
Vaqtga bog‘liq fixture
Expired yoki future obyektlar fixed clock asosida yaratiladi.
Masalan:
expires_at = fixed_now - 1 day
System current time ishlatilsa test yarim tunda yoki timezone farqida beqaror bo‘lishi mumkin.
Database cleanup
Persist qiluvchi mother testdan keyin yaratilgan rowlarni tozalashga yordam berishi mumkin.
Transaction rollback, isolated schema yoki fixture registry ishlatiladi.
Testlar bir-birining data’siga tayanmasligi kerak.
Bog‘liq tushunchalar
Test fixture, Test Data Builder, Factory, Test double, Unit test, Integration test, Test data, Deterministic test, Object creation, Builder Pattern