07 β Test dublyorlari I: taksonomiya¶
π README Β· β¬ οΈ Oldingi: 06 β Test ma'lumotlari: fixture, parametrize, builder Β· Keyingi: 08 β Test dublyorlari II: amaliyot va tuzoqlar β‘οΈ
Bu bobda: kod tashqi dunyoga (ma'lumotlar bazasi, tarmoq, to'lov tizimi, vaqt) bog'langanda uni qanday qilib tez va ishonchli test qilish mumkin β uni dublyor (test double) bilan almashtirib. Gerard Meszaros'ning besh turi β dummy, stub, spy, mock, fake β ni aniq ajratamiz (ko'pchilik bularni chalkashtiradi). Hammasini sof Python klasslar bilan ko'rsatamiz.
Halollik / Eslatma: bu bob β nazariya va taksonomiya. Bu yerda atamalarni va "qachon qaysi turni ishlatish" tushunchasini o'rnatamiz.
unittest.mock,patch, side effect va ortiqcha mock tuzoqlari β keyingi 08-bobda amaliyotda. "Don't mock what you don't own" tamoyilini ham bu yerda boshlaymiz, 08-bobda chuqurlashtiramiz. Barcha Python namunalari haqiqatanpytestbilan ishga tushirib, chiqishi tekshirilgan.
Muammo: kod yolg'iz emas¶
Tasavvur qiling, buyurtmani_yakunla() funksiyasini yozdingiz. U mahsulot narxlarini
ma'lumotlar bazasidan oladi, jamini hisoblaydi, so'ng buyurtmani yana bazaga saqlaydi,
va xaridorga email yuboradi. Endi unga test yozmoqchisiz. Lekin:
- Sekin β har test real bazaga ulanadi, email serveriga so'rov yuboradi (sekundlar, minutlar).
- Ishonchsiz β tarmoq tushib qolsa, baza band bo'lsa, test "yiqiladi" β kodingiz aybsiz bo'lsa ham.
- Yon-effektli β har test ishga tushganda haqiqiy email ketadi, baza o'zgaradi. Buni xohlamaysiz.
- Boshqarib bo'lmaydi β "agar to'lov rad etilsa nima bo'ladi?" holatini real tizimda yuzaga keltirish qiyin.
Yechim β kino dublyori (caskadyor) kabi. Xavfli sahnada aktyor o'rniga dublyor tushadi: u xuddi aktyorga o'xshaydi, kameraga o'sha rolni o'ynaydi, lekin haqiqiy emas. Testda ham real ma'lumotlar bazasi o'rniga dublyor qo'yamiz: u o'sha interfeysni taqlid qiladi, lekin tez, boshqariladigan va xavfsiz.
SUT va DOC: ikkita asosiy atama¶
Dublyorlar haqida gaplashish uchun ikkita atama kerak:
- SUT (System Under Test β sinaladigan tizim): hozir test qilayotgan kodingiz. Bizning
misolda β
buyurtma_jami()funksiyasi. - DOC (Depended-On Component β bog'liq komponent): SUT tayanadigan tashqi narsa. Bizning
misolda β
Ombor(baza). Aynan DOC ni dublyor bilan almashtiramiz, SUT ni emas.
Diqqat: SUT hech qachon o'zgarmaydi. Biz uni atrofini o'zgartiramiz. Agar testni o'tkazish uchun SUT kodini o'zgartirishingizga to'g'ri kelsa β bu dizayn muammosi (10-bobda "testlanadigan dizayn"). Yaxshi loyihalashtirilgan kod DOC ni tashqaridan qabul qiladi (dependency injection), shuning uchun uni almashtirish oson bo'ladi.
Besh tur: Meszaros taksonomiyasi¶
"Mock" so'zi kundalik tilda hamma soxta obyekt uchun ishlatiladi. Lekin Gerard Meszaros ("xUnit Test Patterns" kitobi muallifi) ularni beshta aniq turga ajratdi. Bu farqni bilish muhim: har turning o'z maqsadi bor, va noto'g'ri turni tanlash mo'rt yoki ma'nosiz testga olib keladi.
Umumiy atama β Test Double (test dublyori). Besh turi:
| Tur | Nima qiladi | Kirish beradimi? | Yozadimi? | O'zi tekshiradimi? |
|---|---|---|---|---|
| Dummy | hech narsa β o'rin to'ldiradi | yo'q | yo'q | yo'q |
| Stub | tayyor javob qaytaradi | β ha | yo'q | yo'q |
| Spy | stub + chaqiruvlarni yozadi | β ha | β ha | yo'q (siz tekshirasiz) |
| Mock | kutish bilan dasturlanadi | ba'zan | β ha | β ha (o'zi verify) |
| Fake | ishlaydigan soddalashtirilgan nusxa | β ha | β ha | yo'q |
Endi har birini sof Python bilan ko'rsatamiz. Avval bizga umumiy bir interfeys kerak β Ombor.
Bu β bizning DOC:
# Sinaladigan kod (production)
class Ombor:
"""Real ombor interfeysi. Test paytida bunga bog'lanmaymiz."""
def narx(self, mahsulot_id):
raise NotImplementedError
def saqla(self, buyurtma):
raise NotImplementedError
# SUT: savatchadagi har mahsulot narxini ombordan olib jamlaydi
def buyurtma_jami(ombor, savatcha):
jami = 0
for mahsulot_id, dona in savatcha.items():
jami += ombor.narx(mahsulot_id) * dona
return jami
Dummy β faqat o'rin to'ldiruvchi¶
Dummy hech qachon ishlatilmaydi. U faqat bir funksiya/konstruktor majburiy argument talab qilgani uchun beriladi, lekin shu test yo'lida hech qachon chaqirilmaydi.
class DummyLogger:
pass # hech qachon chaqirilmaydi β faqat argumentni to'ldiradi
# Misol: funksiya logger talab qiladi, lekin bu testda log yo'li tegmaydi
hisobchi = Hisobchi(logger=DummyLogger()) # logger shunchaki "bor bo'lishi" kerak
Agar dummy chaqirilsa (
NotImplementedErroryokiAttributeErrorbilan yiqilsa) β bu yaxshi signal: demak u aslida dummy emas edi, sizga stub kerak ekan.
Stub β tayyor javob qaytaradi¶
Stub SUT ga oldindan tayyorlangan qiymat beradi. U "kirish" manbai: SUT ga ma'lumot uzatadi, lekin hech narsa yozmaydi va tekshirmaydi.
class OmborStub(Ombor):
def __init__(self, narxlar):
self._narxlar = narxlar
def narx(self, mahsulot_id):
return self._narxlar[mahsulot_id] # tayyor javob
def saqla(self, buyurtma):
pass # stub uchun ahamiyatsiz
Spy β stub ustiga yozuv¶
Spy stub kabi javob beradi, lekin qaysi chaqiruvlar bo'lganini yozib boradi. Keyin siz testda o'sha yozuvni tekshirasiz.
class OmborSpy(Ombor):
def __init__(self, narxlar):
self._narxlar = narxlar
self.saqlangan = [] # yozuv jurnali
def narx(self, mahsulot_id):
return self._narxlar[mahsulot_id]
def saqla(self, buyurtma):
self.saqlangan.append(buyurtma) # chaqiruvni yozib boramiz
Mock β kutish bilan dasturlangan, o'zi verify qiladi¶
Mock β eng "qattiq" tur. U oldindan kutish (expectation) bilan dasturlanadi: "saqla() aynan
shu argument bilan chaqirilishi kerak". Keyin o'zi tekshiradi (verify).
class OmborMock(Ombor):
def __init__(self, kutilgan_saqlash):
self._kutilgan = kutilgan_saqlash
self._haqiqiy = None
def narx(self, mahsulot_id):
return 0
def saqla(self, buyurtma):
self._haqiqiy = buyurtma
def verify(self): # o'zi tekshiradi
assert self._haqiqiy == self._kutilgan, \
f"kutilgan {self._kutilgan}, lekin {self._haqiqiy}"
Stub va mock farqi (eng muhim nuqta): ikkalasi ham soxta obyekt, lekin maqsadi boshqa. Stub test uchun kirish beradi (natijaga qaraysiz). Mock test uchun tekshirilayotgan narsa: uning chaqirilishi testning o'zi shart bo'lgan natija. "Bu obyekt qanday javob beradi" β stub. "Bu obyekt to'g'ri chaqirildimi" β mock.
Fake β ishlaydigan, soddalashtirilgan nusxa¶
Fake β haqiqiy ishlovchi implementatsiya, lekin production'ga yaroqsiz darajada soddalashtirilgan. Klassik misol β real ma'lumotlar bazasi o'rniga xotiradagi lug'at (in-memory).
class FakeOmbor(Ombor):
def __init__(self):
self._narxlar = {}
self._buyurtmalar = []
def narx_ornat(self, mahsulot_id, qiymat):
self._narxlar[mahsulot_id] = qiymat
def narx(self, mahsulot_id):
return self._narxlar[mahsulot_id]
def saqla(self, buyurtma):
self._buyurtmalar.append(buyurtma) # haqiqatan saqlaydi (xotirada)
Eslatma: fake'ning xulqi haqiqiy β yozsangiz keyin o'qiy olasiz. Stub'da bunday "yodda saqlash" mantig'i yo'q. Shuning uchun fake murakkab ssenariylar uchun (ko'p chaqiruv, holat o'zgarishi) eng realistik, lekin yozish ham qimmatroq.
State verification vs behavior verification¶
Dublyor tanlash aslida bitta savolga bog'liq: nimani tasdiqlamoqchisiz?
- State verification (holatni tekshirish): SUT ni ishga tushiring va qaytgan qiymat yoki yangi holat to'g'rimi β shunga qarang. Bunga stub yoki fake mos.
- Behavior verification (xulqni tekshirish): SUT DOC bilan qanday muloqot qildi β qaysi metod, qanday argument bilan, necha marta chaqirildi β shunga qarang. Bunga spy yoki mock mos.
Bitta savatchada ikkalasini ham ko'raylik. Avval state (stub bilan):
def test_jami_stub_bilan_natijani_tekshiradi():
# Arrange
ombor = OmborStub({"non": 5000, "sut": 8000})
# Act
jami = buyurtma_jami(ombor, {"non": 2, "sut": 1})
# Assert β natijaga (holatga) qaraymiz
assert jami == 18000
# -> PASSED
Endi behavior (spy bilan). Buning uchun yon-effektli SUT kerak β buyurtmani saqlaydigan:
def buyurtmani_yakunla(ombor, savatcha):
jami = buyurtma_jami(ombor, savatcha)
ombor.saqla({"savatcha": savatcha, "jami": jami}) # yon-effekt
return jami
def test_yakunlash_saqlashni_chaqiradi_spy_bilan():
# Arrange
spy = OmborSpy({"non": 5000})
# Act
buyurtmani_yakunla(spy, {"non": 3})
# Assert β xulqqa qaraymiz: saqla() bir marta, to'g'ri jami bilan chaqirildi
assert len(spy.saqlangan) == 1
assert spy.saqlangan[0]["jami"] == 15000
# -> PASSED
Va fake ikkalasini ham qila oladi β natijani ham, saqlangan holatni ham:
def test_yakunlash_fake_bilan_holat_va_yon_effekt():
# Arrange
ombor = FakeOmbor()
ombor.narx_ornat("non", 5000)
# Act
jami = buyurtmani_yakunla(ombor, {"non": 2})
# Assert β natija + saqlangan holat
assert jami == 10000
assert ombor._buyurtmalar[0]["jami"] == 10000
# -> PASSED
Uchchala test ham haqiqatan o'tdi:
test_07.py::test_jami_stub_bilan_natijani_tekshiradi PASSED [ 33%]
test_07.py::test_yakunlash_saqlashni_chaqiradi_spy_bilan PASSED [ 66%]
test_07.py::test_yakunlash_fake_bilan_holat_va_yon_effekt PASSED [100%]
======================== 3 passed in 0.97s ========================
Trade-off: state verification odatda afzal β u nima qilinganini emas, natijani tasdiqlaydi, shuning uchun kod ichi o'zgarsa (refactoring) test buzilmaydi. Behavior verification esa ba'zida yagona yo'l: agar SUT faqat yon-effekt qilsa (email yuboradi, log yozadi) va qaytaradigan qiymati bo'lmasa, "to'g'ri chaqirildimi?" dan boshqa tekshiriladigan narsa yo'q. Lekin uni ortiqcha ishlatish testni implementatsiyaga "yopishtiradi" (pastda).
Klassik vs London: ikki maktab¶
Qachon real obyekt, qachon dublyor ishlatish kerak? Bu savolda ikki "maktab" bor:
| Klassik (Chicago / Detroit) | London (mockist) | |
|---|---|---|
| Standart yondashuv | real obyektlardan foydalan | har bog'liqlikni mock qil |
| Dublyor qachon | faqat "noqulay" DOC uchun (DB, tarmoq) | deyarli har joyda |
| Asosiy verifikatsiya | state (natija) | behavior (o'zaro ta'sir) |
| Test izolyatsiyasi | unit = bir nechta klass birga | unit = bitta klass, qolgani mock |
| Afzalligi | refactoring'ga chidamli, realistik | aniq izolyatsiya, dizaynni "tashqaridan" haydaydi |
| Xavfi | yiqilish sababini topish qiyinroq | mo'rt testlar, dizaynni "muzlatadi" |
Klassik maktab: ichki obyektlarni real ishlat, faqat tashqi/sekin chegaralarni almashtir. Natijaga qara. London maktab: har bir hamkorni mock qil, obyektlar bir-biri bilan qanday gaplashishini test qil.
Trade-off β over-specification: behavior verification (ayniqsa London uslubida) testni kodning ichki tafsilotlariga bog'lab qo'yadi. Misol: agar test "
saqla()aniq shu tartibda, aniq shu argument bilan chaqirildi" deb tekshirsa, ertaga siz kodni xuddi o'sha natija bilan, lekin boshqacha yo'l bilan refactor qilsangiz β test yiqiladi, garchi xulq tashqaridan bir xil bo'lsa ham. Mock'lar shu ma'noda dizaynni "muzlatadi". Shuning uchun: avval state'ni sina, behavior'ni faqat zarur bo'lganda (sof yon-effekt) ishlat.Eslatma: bular "to'g'ri/noto'g'ri" emas β uslublar. Ko'p tajribali muhandislar aralash ishlatadi: domen mantig'i uchun klassik (real obyekt + state), tashqi chegaralar (to'lov, email) uchun behavior. Til-mustaqil: bu munozara JavaScript, Java, C# jamoalarida ham aynan shu nom bilan boradi.
"Don't mock what you don't own" (kirish)¶
Bitta amaliy tamoyil bilan yakunlaymiz (08-bobda chuqurlashadi): o'zingizniki bo'lmagan narsani mock qilmang. Ya'ni: tashqi kutubxona yoki uchinchi tomon API'sini to'g'ridan-to'g'ri mock qilmang. Buning o'rniga uni o'zingizning yupqa adapter (o'rab oluvchi) interfeysingiz orqasiga yashiring, va o'sha sizniki bo'lgan interfeysni dublyor bilan almashtiring.
Sababi oddiy: tashqi kutubxona ertaga API'sini o'zgartirsa, sizning mock hali ham eski shaklni
taqlid qiladi β test yashil bo'ladi, lekin production sinadi (mock realdan ajralib ketadi). O'z
interfeysingizni esa siz nazorat qilasiz. Bu yerda Ombor aynan shunday β bizning interfeysimiz,
SQLAlchemy yoki psycopgning xom obyekti emas.
Bu tamoyil va
unittest.mockbilan amaliyot β to'liq 08-bobda. Hozircha shuni yodda tuting: dublyor o'rnatadigan chegara sizning kodingiz nazoratidagi interfeys bo'lsin.
Asosiy g'oyalar (bobni qisqacha)¶
- Tashqi bog'liqlik test uchun muammo β sekin, ishonchsiz, yon-effektli. Yechim: DOC ni dublyor bilan almashtirish.
- SUT o'zgarmaydi, DOC almashtiriladi. Almashtirish oson bo'lishi uchun DOC ni tashqaridan uzating (DI).
- Besh tur (Meszaros): dummy (o'rin to'ldiruvchi), stub (tayyor javob), spy (stub + yozuv), mock (kutish + o'zi verify), fake (ishlaydigan soddalashtirilgan).
- Stub β mock. Stub kirish beradi (natijaga qara). Mock β testning o'zi tekshiradigan narsa (chaqiruv).
- State vs behavior: stub/fake = holatni tekshir (natijaga qara); spy/mock = xulqni tekshir (chaqiruvga qara). State'ni afzal ko'r.
- Klassik vs London: real obyekt + state vs har joyda mock + behavior. Aralash ishlatish odatiy.
- Over-specification xavfi: behavior verification kodni implementatsiyaga bog'laydi va dizaynni "muzlatadi".
- Don't mock what you don't own: o'z adapter interfeysingizni dublyorla, xom tashqi kutubxonani emas.
Mashqlar¶
Oson¶
1-mashq. Quyidagi dublyorlar qaysi turga kiradi? (a) konstruktorga beriladigan, lekin hech
chaqirilmaydigan obyekt; (b) har doim 42 qaytaradigan obyekt; (c) yuborilgan emaillar ro'yxatini
to'playdigan obyekt.
2-mashq. "State verification" va "behavior verification" o'rtasidagi farqni bir jumlada ayting, va har biriga qaysi dublyor turlari mos kelishini yozing.
3-mashq. OmborStub ni shunday yozingki, u faqat "non" uchun 5000 qaytarsin. buyurtma_jami
ni {"non": 4} savatcha bilan chaqirib, natija 20000 ekanini tasdiqlovchi test yozing.
O'rta¶
4-mashq. EmailSpy klassi yozing: yubor(kimga, matn) metodi bo'lsin va u barcha yuborilgan
xatlarni yuborilganlar ro'yxatiga yozsin. Keyin bir foydalanuvchiga ikkita xat yuboradigan
SUT ni test qiling: spy'da aniq 2 ta xat borligini va birinchisi to'g'ri manzilga ketganini tekshiring.
5-mashq. Bitta TolovStub yozing, u tasdiqla() chaqirilganda True qaytarsin (muvaffaqiyatli
to'lov), va ikkinchi TolovStub yozing, u False qaytarsin (rad etilgan to'lov). Har biri bilan
SUT (buyurtmani_jonat) ning to'g'ri tarmoqlanishini ko'rsating.
6-mashq. FakeOmbor ga o'chir(buyurtma_id) metodini qo'shing. Saqlab, keyin o'chirib, so'ng
o'qishga urinilganda xato bo'lishini tasdiqlovchi test yozing (fake = ishlaydigan, holatli implementatsiya).
Qiyin¶
7-mashq. Bir vaziyat: SUT narx() ni chaqiradi, natijani qaytaradi, va saqla() ni ham
chaqiradi. Buni (a) faqat state tekshiradigan test bilan, (b) faqat behavior tekshiradigan
test bilan yozing. Ikkala testni ham yozgach, qaysi biri kodni keyinchalik refactor qilganda
osonroq buzilishini va nima uchun ekanini tushuntiring (over-specification).
8-mashq. "Don't mock what you don't own" buzilgan stsenariyni keltirib chiqaring: tasavvur qiling,
tashqi tolov_api.charge(...) funksiyasini to'g'ridan-to'g'ri mock qildingiz, test yashil. Ertaga
kutubxona metodni charge dan create_charge ga o'zgartirdi. Nima bo'ladi? Endi bu xatoni
oldini oladigan adapter dizaynini (interfeys + ishlaydigan tekshiruv) yozing.
Yechimlar
1-mashq yechimi¶
(a) Dummy β beriladi, lekin chaqirilmaydi. (b) Stub β tayyor (hardcode) javob qaytaradi. (c) Spy β chaqiruvlarni (yuborilgan xatlarni) keyin tekshirish uchun yozib boradi.
2-mashq yechimi¶
State verification β SUT ishga tushgach natija/holat to'g'rimi (qaytgan qiymatga qaraysiz); behavior verification β SUT DOC bilan qanday muloqot qildi (qaysi metod, qanday argument bilan chaqirildi). State'ga stub va fake, behavior'ga spy va mock mos keladi.
3-mashq yechimi¶
class OmborStub:
def narx(self, mahsulot_id):
return 5000 # faqat "non" uchun ishlatamiz
def buyurtma_jami(ombor, savatcha):
return sum(ombor.narx(m) * d for m, d in savatcha.items())
def test_non_jami():
jami = buyurtma_jami(OmborStub(), {"non": 4})
assert jami == 20000
# -> PASSED
4-mashq yechimi¶
class EmailSpy:
def __init__(self):
self.yuborilganlar = []
def yubor(self, kimga, matn):
self.yuborilganlar.append((kimga, matn))
def ikki_xat_yubor(email, manzil):
email.yubor(manzil, "Salom")
email.yubor(manzil, "Buyurtmangiz qabul qilindi")
def test_ikkita_xat_yuborildi():
spy = EmailSpy()
ikki_xat_yubor(spy, "ali@example.com")
assert len(spy.yuborilganlar) == 2 # behavior: necha marta
assert spy.yuborilganlar[0][0] == "ali@example.com" # birinchisi to'g'ri manzilga
# -> PASSED
5-mashq yechimi¶
class TolovTasdiq:
def tasdiqla(self): return True
class TolovRad:
def tasdiqla(self): return False
def buyurtmani_jonat(tolov):
if tolov.tasdiqla():
return "jonatildi"
return "rad etildi"
def test_tolov_tasdiqlansa_jonatiladi():
assert buyurtmani_jonat(TolovTasdiq()) == "jonatildi"
def test_tolov_rad_etilsa_jonatilmaydi():
assert buyurtmani_jonat(TolovRad()) == "rad etildi"
# -> 2 passed
Ikki stub β ikki holat (state-based): har biri SUT ga turli kirish berib, tarmoqlanishni sinaydi.
6-mashq yechimi¶
class FakeOmbor:
def __init__(self):
self._buyurtmalar = {}
self._id = 1
def saqla(self, buyurtma):
bid = self._id
self._buyurtmalar[bid] = buyurtma
self._id += 1
return bid
def ochir(self, buyurtma_id):
del self._buyurtmalar[buyurtma_id]
def oqi(self, buyurtma_id):
return self._buyurtmalar[buyurtma_id]
def test_ochirilgach_oqib_bolmaydi():
ombor = FakeOmbor()
bid = ombor.saqla({"mahsulot": "non"})
ombor.ochir(bid)
import pytest
with pytest.raises(KeyError):
ombor.oqi(bid)
# -> PASSED
Fake holatni haqiqatan boshqaradi β saqlash, o'chirish, o'qish ketma-ketligi real ishlaydi.
7-mashq yechimi¶
class OmborSpy:
def __init__(self):
self.saqlangan = []
def narx(self, m): return 5000
def saqla(self, b): self.saqlangan.append(b)
def yakunla(ombor, savatcha):
jami = sum(ombor.narx(m) * d for m, d in savatcha.items())
ombor.saqla({"jami": jami})
return jami
# (a) STATE β faqat natija
def test_state():
spy = OmborSpy()
jami = yakunla(spy, {"non": 2})
assert jami == 10000
# (b) BEHAVIOR β chaqiruv
def test_behavior():
spy = OmborSpy()
yakunla(spy, {"non": 2})
assert spy.saqlangan == [{"jami": 10000}]
# -> 2 passed
Behavior testi (b) osonroq buziladi. Agar ertaga saqla() ga uzatiladigan lug'atga yangi
maydon qo'shsangiz (masalan {"jami": 10000, "sana": ...}), test_behavior darhol yiqiladi β
chunki u aniq shaklni kutadi. test_state esa o'zgarmaydi: natija hali ham 10000. Bu β
over-specification: behavior test kodning ichki tafsilotiga "yopishib" qoladi.
8-mashq yechimi¶
To'g'ridan-to'g'ri tolov_api.charge ni mock qilsangiz: kutubxona uni create_charge ga
o'zgartirgach, mock hali ham eski charge ni taqlid qiladi, test yashil β lekin production'da
AttributeError. Test sizni himoya qilmadi, chunki mock real bilan ajralib ketdi.
Yechim β o'zingizning adapter interfeysingiz (sizniki = mock qilishga ruxsat):
# Sizning interfeysingiz (port) β buni nazorat qilasiz
class Tolov:
def tasdiqla(self, summa):
raise NotImplementedError
# Real adapter (production): tashqi API'ni o'rab oladi.
# Kutubxona charge -> create_charge bo'lsa, FAQAT shu yer o'zgaradi.
class RealTolov(Tolov):
def __init__(self, api):
self._api = api
def tasdiqla(self, summa):
return self._api.create_charge(summa) # yangi nom β bitta joyda
# Test: SIZNING interfeysingizni dublyorlaymiz, xom kutubxonani emas
class TolovStub(Tolov):
def tasdiqla(self, summa):
return True
def buyurtmani_jonat(tolov, summa):
return "jonatildi" if tolov.tasdiqla(summa) else "rad etildi"
def test_adapter_orqali():
assert buyurtmani_jonat(TolovStub(), 10000) == "jonatildi"
# -> PASSED
Endi kutubxona API'si o'zgarsa β RealTolov ichida bitta qator tuzatiladi, testlaringizga
tegmaydi. Adapter "sizniki" bo'lgani uchun uni dublyorlash xavfsiz.
π README Β· β¬ οΈ Oldingi: 06 β Test ma'lumotlari: fixture, parametrize, builder Β· Keyingi: 08 β Test dublyorlari II: amaliyot va tuzoqlar β‘οΈ