05 β Assertion'lar va test holatlarini tanlash¶
π README Β· β¬ οΈ Oldingi: 04 β Yaxshi test xossalari Β· Keyingi: 06 β Fixture va parametrize β‘οΈ
Bu bobda: ikki katta savolga javob beramiz β nimani tekshirish va qaysi holatlarni sinash. Avval
assertning turlarini (tenglik, taxminiy tenglik, tarkib, istisno) ko'rib chiqamiz, keyin esa boshlovchini eng ko'p qiynaydigan savolni yechamiz: "qancha test yozsam yetadi va aynan qaysi qiymatlarni tanlayman?" Buning uchun ikkita kuchli texnika β ekvivalentlik sinflari va chegara qiymatlari β bilan tanishamiz.Halollik / Eslatma: bu bob bitta funksiya darajasidagi (unit) testlarga qaratilgan. Mock va xulq-tekshirishga faqat ko'prik tashlaymiz β to'liq mavzu 07 va 08-bobda. "Qancha test yetarli?" savoliga aniq raqamli javob yo'q; coverage (20-bob) va mutation (22-bob) bunga signal beradi, lekin ularni keyin ko'ramiz. Barcha Python namunalari
pytestbilan haqiqatan ishga tushirilib, chiqishi tekshirilgan (Python 3.14, pytest 9.0).
Assertion β testning yuragi¶
Eslang, 02-bobda test uch qadamdan iborat edi: Arrange (tayyorla), Act (bajar), Assert (tasdiqla). Mana shu oxirgi qadam β assertion β testning haqiqiy "hukmi". Agar Act bosqichi kodni ishga tushirsa, Assert bosqichi "natija aynan men kutgan narsami?" degan savolga ha yoki yo'q deb javob beradi. Yo'q bo'lsa β test yiqiladi.
Bu xuddi mashinani sotib olishdan oldin uni tekshirishga o'xshaydi: dvigatel ishladi (Act), endi moy darajasi to'g'rimi, tormoz ushlaydimi, signal chalindimi β bularning har biri alohida tasdiq. Bitta tekshirib ko'rmagan narsangiz keyin muammoga aylanishi mumkin.
pytest'da assertion oddiy Python assert so'zi bilan yoziladi β alohida assertEqual kabi metodlar
shart emas. Buning sehri shundaki, test yiqilganda pytest assert ifodasini ichidan ochib
(introspection) sizga aniq nima nimaga teng emasligini ko'rsatadi.
Ishga tushiramiz β pytest faqat "yiqildi" demaydi, balki qiymatlarni ham ko'rsatadi:
assert 4 == 5 β mana shu introspection. Boshqa tillarda buni assertEquals(5, natija) kabi maxsus
funksiya beradi (JS'da expect(natija).toBe(5), PHP'da $this->assertEquals(5, $natija)); pytest esa
oddiy assertni "aqlli" qiladi.
Assertion turlari¶
Bitta == bilan hamma narsani tekshirib bo'lmaydi. Quyida eng ko'p kerak bo'ladigan tasdiq turlari.
Tenglik va xabar qo'shish¶
Eng oddiy va eng ko'p ishlatiladigani β ==. Unga izoh (xabar) qo'shsangiz, test yiqilganda
sabab tezroq tushunarli bo'ladi:
Vergulndan keyingi matn faqat yiqilganda ko'rsatiladi. Murakkab shartlarda bu juda foydali:
"assert False" o'rniga "assert balans >= 0, 'balans manfiy bo'lib qoldi'" ni o'qish osonroq.
Maslahat: introspection allaqachon qiymatlarni ko'rsatadi, shuning uchun oddiy
==ga izoh shart emas. Izohni mantiqiy (and/or/>) yoki noaniq shartlarda qo'shing β u yerda pytest faqatassert Falsedeb ko'rsatib, nega yiqilganini aytmaydi.
Taxminiy tenglik β float tuzog'i¶
Mana eng mashhur tuzoq. Kompyuter kasr (float) sonlarni aniq saqlamaydi:
Ha, 0.1 + 0.2 aniq 0.3 emas! Agar shunchaki assert narx == 0.3 yozsangiz, test
tushunarsiz sababga ko'ra yiqiladi. Yechim β taxminiy tenglik: pytest.approx.
pytest.approx kichik bardoshlilik (tolerance) bilan solishtiradi. Pul, o'lchov, foiz β har qanday
kasr hisob-kitobda doimo approx ishlating. Boshqa tillarda ekvivalenti bor: JS'da
expect(x).toBeCloseTo(0.3), Java'da assertEquals(0.3, x, 1e-9).
Diqqat: butun sonlar (
int) bilan bunday muammo yo'q β2 + 3 == 5har doim aniq.approxfaqat float uchun.
Tarkib: ro'yxat, to'plam, in¶
Ko'pincha "natijada falon element bormi?" yoki "ikki to'plam bir xilmi?" deb tekshiramiz:
def test_royxat_va_in():
savat = ["non", "sut", "tuxum"]
assert "sut" in savat # element bormi?
assert len(savat) == 3 # uzunlik to'g'rimi?
def test_toplam_tarkibi():
natija = {"a", "b", "c"}
assert natija == {"c", "b", "a"} # tartib muhim emas -> PASS
set (to'plam) bilan solishtirish tartibni e'tiborsiz qoldiradi β bu juda foydali, chunki
ko'pincha "shu uchta element bo'lsin, tartibi muhim emas" demoqchi bo'lamiz. Ro'yxat (list) esa
tartibni hisobga oladi.
Mantiqiy shartlar¶
Bir nechta shartni birlashtirib ham tekshirsa bo'ladi:
Trade-off: bitta
assertga juda ko'p shart tiqishtirmang. Yiqilganda qaysi shart buzilganini bilish qiyinlashadi (bu 04-bobdagi "bitta yiqilish sababi" tamoyiliga zid). Ko'p shart bo'lsa, ularni alohidaassertlarga bo'ling yoki aniq izoh qo'shing.
Yuqoridagi olti testni bitta faylda yig'ib ishlatganda:
Istisnolarni (exception) testlash¶
Yaxshi kod nafaqat to'g'ri ishlaganda to'g'ri natija berishi, balki noto'g'ri kirishda
to'g'ri xato ko'tarishi ham kerak. "Funksiya nol bo'lganda ValueError chiqaradimi?" β buni ham
testlash shart. Buning uchun pytest.raises ishlatamiz.
Test:
import pytest
def test_oddiy_bolish():
assert bol(10, 2) == 5
def test_nolga_bolish_istisno():
with pytest.raises(ValueError):
bol(10, 0) # bu yerda ValueError chiqishi SHART
with pytest.raises(ValueError): bloki "ichidagi kod aynan shu istisnoni ko'tarsin" deydi. Agar
istisno chiqmasa β test yiqiladi (kod buzilgan!). Agar boshqa istisno chiqsa β u ham yiqiladi.
Xato matnini tekshirish (match=)¶
Ba'zan ValueError chiqishining o'zi kam β uning xabari ham to'g'ri bo'lsin. match= parametri
xabarni (regular ifoda bilan) tekshiradi:
def test_nolga_bolish_xabar_matni():
with pytest.raises(ValueError, match="nolga"):
bol(1, 0)
def test_istisno_obyekti():
with pytest.raises(ValueError) as xato:
bol(1, 0)
assert "bo'lib bo'lmaydi" in str(xato.value)
as xato orqali istisno obyektining o'ziga yetib, undagi ma'lumotni batafsil tekshirsa bo'ladi.
Eslatma: xato matnini juda qattiq tekshirmang. Agar
match="nolga bo'lib bo'lmaydi"deb butun jumlani yozsangiz, kelajakda xabarni biroz tahrir qilganingizda test ham yiqiladi β bu "mo'rt test" (fragile test, 04-bob). Xabardagi kalit so'zni tekshiring, butun jumlani emas.
Holat (state) vs xulq (behavior) tekshirish¶
Tekshirishning ikki uslubi bor:
| Uslub | Nimani tekshiramiz | Qachon |
|---|---|---|
| Holat (state) | Funksiya qaytargan qiymat yoki obyekt o'zgargan holati | Funksiya natija qaytarsa |
| Xulq (behavior) | Funksiya boshqa narsani chaqirgani (effekt) | Funksiya tashqi narsaga ta'sir qilsa |
Misol bilan ko'raylik:
from unittest.mock import Mock
def qoshish(a, b):
return a + b # holat: qiymat qaytaradi
def xush_kelibsiz(foydalanuvchi, xabarchi):
xabarchi.yubor(foydalanuvchi, "Xush kelibsiz!") # xulq: tashqi xizmatni chaqiradi
def test_holat_tekshirish():
# Holat: faqat qaytgan qiymatga qaraymiz
assert qoshish(2, 3) == 5
def test_xulq_tekshirish():
# Xulq: chaqiruv sodir bo'lganini tekshiramiz
soxta_xabarchi = Mock()
xush_kelibsiz("Olim", soxta_xabarchi)
soxta_xabarchi.yubor.assert_called_once_with("Olim", "Xush kelibsiz!")
Birinchi test β sof holat: kirish berdik, chiqishni solishtirdik. Ikkinchi test esa xizmat (email
yuboruvchi) chaqirilganini tekshiradi β bu xulq. Bu yerda Mock β soxta dublyor; uni
to'liq 07β08-bobda ochamiz.
Maslahat: imkon bo'lsa, holatni tekshirishni afzal ko'ring β u soddaroq va mustahkamroq. Xulq-tekshirish kodning ichki tuzilishiga bog'lanib qoladi (qaysi metodni chaqirgani). Faqat natijani holat orqali ko'rib bo'lmaganda (masalan, email yuborildi) xulqqa o'ting.
Test holatlarini tanlash: nimani sinaymiz?¶
Endi eng muhim savol. Funksiyani yozdingiz β qaysi kirishlar bilan test yozasiz? Boshlovchilar odatda bitta "ishlaydigan" misol yozib qo'yib, "test bor" deb o'ylaydi. Lekin bitta misol kodning chetlaridagi xatolarni tutmaydi.
Yaxshi xabar: cheksiz kirish bo'lsa-da, ularning hammasini test qilish shart emas. Ikkita texnika kirishlar okeanidan eng "foydali" bir nechtasini ajratib beradi.
1. Ekvivalentlik sinflari (equivalence partitioning)¶
G'oya: kirishlarni "bir xil ishlov ko'radigan" guruhlarga bo'ling. Agar funksiya 18 va 40 yoshni bir xil ishlasa (ikkalasi ham 10% chegirma), unda 18, 25, 40, 63 ni alohida-alohida test qilish ortiqcha β ularning bittasi guruh vakili bo'la oladi.
Har guruhdan bitta vakil tanlaysiz. Bu test sonini keskin kamaytiradi, lekin qamrovni saqlaydi.
2. Chegara qiymatlari (boundary value analysis)¶
Mana hayotiy haqiqat: xatolar chegarada yashaydi. Dasturchi < o'rniga <= yozadi, 65 o'rniga
64 deb adashadi β bunday xatolar deyarli doim sinflar chegarasida sodir bo'ladi, ularning
o'rtasida emas.
Shuning uchun har sinf chegarasini va uning ikki tomonidagi qiymatlarni sinang:
0,-1,1(nol atrofida)max,max + 1(yuqori chegara)- bo'sh ro'yxat, bitta elementli ro'yxat
- sinflar tutashgan nuqtalar:
17va18,64va65
Bu "off-by-one" (bir-birga adashish) xatolarni tutadigan eng kuchli texnika.
3. Maxsus va ekstremal holatlar¶
Chegaralardan tashqari, "g'alati" kirishlarni ham unutmang:
- bo'sh (
"",[],{}) vaNone - manfiy sonlar, nol
- juda katta qiymat (uzun satr, ulkan ro'yxat)
- Unicode, bo'sh joy, takrorlanuvchi elementlar
4. Ijobiy (happy path) + salbiy (error path)¶
Har funksiyada kamida ikki yo'l bor: to'g'ri ishlaydigan holat (happy path) va xato holat (error path). Ko'p boshlovchilar faqat happy path'ni yozadi β natijada kod noto'g'ri kirishda jim-jit buziladi. Ikkalasini ham yozing.
To'liq misol: yosh bo'yicha chegirma¶
Endi bu texnikalarni birlashtiramiz. Talab quyidagicha:
yosh < 0β xato (ValueError)0β17yosh β chegirma yo'q (0%)18β64yosh β 10% chegirma65va undan katta β 20% chegirma
# chegirma.py β sinaladigan kod
def chegirma(yosh):
"""Yosh bo'yicha chegirma foizini qaytaradi."""
if yosh < 0:
raise ValueError("yosh manfiy bo'lishi mumkin emas")
if yosh <= 17:
return 0
if yosh <= 64:
return 10
return 20
Endi ekvivalentlik + chegara bilan test holatlarini tuzamiz. To'rt sinf bor (xato, 0%, 10%, 20%),
ularning chegaralari 0, 17/18, 64/65. Mana to'liq to'plam (parametrize haqida batafsil
06-bobda, hozir uni "bitta testni ko'p kirish bilan" deb tushuning):
# test_chegirma.py
import pytest
from chegirma import chegirma
@pytest.mark.parametrize("yosh, kutilgan", [
(0, 0), # chegara: eng kichik amaldagi yosh
(17, 0), # chegara: "yo'q" sinfining yuqori cheti
(18, 10), # chegara: "10%" sinfining quyi cheti
(40, 10), # vakil: o'rta yosh
(64, 10), # chegara: "10%" sinfining yuqori cheti
(65, 20), # chegara: "20%" sinfining quyi cheti
(90, 20), # vakil: keksa yosh
])
def test_chegirma_ijobiy(yosh, kutilgan):
assert chegirma(yosh) == kutilgan
def test_manfiy_yosh_xato():
with pytest.raises(ValueError, match="manfiy"):
chegirma(-1)
Diqqat qiling: har sinfdan vakil (40, 90) va har chegara (0, 17, 18, 64, 65) bor, plus error path (manfiy yosh). Atigi 8 ta test β lekin ular butun mantiqni qoplaydi. Ishga tushiramiz:
test_chegirma.py::test_chegirma_ijobiy[0-0] PASSED [ 12%]
test_chegirma.py::test_chegirma_ijobiy[17-0] PASSED [ 25%]
test_chegirma.py::test_chegirma_ijobiy[18-10] PASSED [ 37%]
test_chegirma.py::test_chegirma_ijobiy[40-10] PASSED [ 50%]
test_chegirma.py::test_chegirma_ijobiy[64-10] PASSED [ 62%]
test_chegirma.py::test_chegirma_ijobiy[65-20] PASSED [ 75%]
test_chegirma.py::test_chegirma_ijobiy[90-20] PASSED [ 87%]
test_chegirma.py::test_manfiy_yosh_xato PASSED [100%]
============================== 8 passed in 1.01s ==============================
Chegara xatosini jonli tutamiz¶
Endi eng qiziq qismi. Tasavvur qiling, dasturchi keksalik chegarasini noto'g'ri yozdi β >= 65
o'rniga > 65 deb (juda keng tarqalgan off-by-one xato):
# chegirma_xato.py β ICHIDA XATO bor
def chegirma(yosh):
if yosh < 0:
raise ValueError("yosh manfiy bo'lishi mumkin emas")
if yosh <= 17:
return 0
if yosh > 65: # XATO: aynan 65 yoshli ham 20% olishi kerak edi
return 20
return 10
Bu kod 64, 70, 90 yosh bilan to'g'ri ishlaydi β agar siz chegarani test qilmagan bo'lsangiz,
xato yashirin qoladi! Lekin bizning to'plamda (65, 20) chegara holati bor. Ishlatamiz:
.....F. [100%]
_________________________ test_chegirma_ijobiy[65-20] _________________________
def test_chegirma_ijobiy(yosh, kutilgan):
> assert chegirma(yosh) == kutilgan
E assert 10 == 20
E + where 10 = chegirma(65)
FAILED test_chegirma_xato.py::test_chegirma_ijobiy[65-20] - assert 10 == 20
1 failed, 6 passed in 1.15s
Mana! assert 10 == 20 where 10 = chegirma(65) β test aniq 65 yoshda xatoni topdi va introspection
bizga chegirma(65) noto'g'ri 10 qaytarganini ko'rsatdi. Chegara qiymati bo'lmasa, bu xato
ishlab chiqarishga (production) sirg'alib o'tib ketardi. Tuzatish β > 65 ni <= 64 mantiqiga
qaytarish (asl to'g'ri versiyadagidek), shunda 65 yosh return 20 ga tushadi.
Saboq: test soni emas, holat sifati muhim. 100 ta tasodifiy yosh bilan test yozsangiz ham, agar ularning birortasi aynan 65 bo'lmasa, bu xatoni topa olmaysiz. 8 ta o'ylab tanlangan chegara holati esa topadi.
Qancha test yetarli?¶
Eng ko'p beriladigan savol β va eng nozik javob. Aniq raqam yo'q, lekin yo'riq bor:
- Har ekvivalentlik sinfidan kamida bitta vakil.
- Har chegarani (ikki tomonidan) sinang.
- Happy path + har error path.
- Maxsus holatlar (bo'sh,
None, juda katta) qaerda mantiqan mumkin bo'lsa.
Bu yetarli yoki yo'qligini ikkita kuchli vosita o'lchaydi: code coverage (20-bob)
qaysi qatorlar umuman ishlatilmaganini ko'rsatadi, mutation testing (22-bob)
esa testlaringiz xatoni haqiqatan tuta oladimi (masalan, > ni >= ga aylantirsa, test yiqiladimi)
deb tekshiradi. Lekin esda tuting: 100 ta sayoz test 8 ta o'ylangan testdan yomonroq. Soni emas,
sifati β to'g'ri chegara va sinflarni qoplagani β muhim.
Asosiy g'oyalar (bobni qisqacha)¶
- Assert β testning hukmi. pytest oddiy
assertni introspection bilan kuchaytiradi: yiqilgandaassert 4 == 5kabi aniq qiymatlarni ko'rsatadi. - Float'ni hech qachon
==bilan solishtirmang.0.1 + 0.2 != 0.3.pytest.approxishlating. - Istisnolarni
pytest.raisesbilan testlang. Xato matninimatch=orqali, lekin kalit so'z darajasida (butun jumlani emas β mo'rtlik). - Xabar qo'shing (
assert x, "izoh") murakkab/mantiqiy shartlarda; oddiy==ga shart emas. - Holat vs xulq. Imkon bo'lsa qaytgan qiymatni (holat) tekshiring; effektni (email yuborildi) xulq orqali β bu mock'ga olib boradi (07β08-bob).
- Ekvivalentlik sinflari kirishlarni guruhlaydi β har guruhdan bitta vakil yetarli.
- Chegara qiymatlari xatolarni eng samarali tutadi: xatolar chetda (
0,17/18,64/65,max) yashaydi. Off-by-one β eng keng tarqalgan xato. - Happy path + error path β har ikkalasini yozing.
- Test soni emas, sifati. O'ylab tanlangan bir nechta holat tasodifiy yuzta holatdan kuchliroq.
Mashqlar¶
Oson¶
1-mashq. 0.1 + 0.2 == 0.3 nega False qaytaradi? Buni testda to'g'ri tekshirish uchun qaysi
vositadan foydalanasiz va nega?
2-mashq. Quyidagi funksiya manfiy songa ValueError ko'taradi. Uni pytest.raises bilan
tekshiradigan test yozing (xato matnida "manfiy" so'zi borligini ham tekshiring):
def kvadrat_ildiz(x):
if x < 0:
raise ValueError("manfiy sondan ildiz chiqarib bo'lmaydi")
return x ** 0.5
3-mashq. baho(ball) funksiyasi: ball < 0 yoki ball > 100 β xato; 0β59 β "yiqildi";
60β100 β "o'tdi". Ekvivalentlik sinflarini sanang. Har sinf uchun bitta vakil va har chegara uchun
qiymat tanlang (test yozmang, faqat qiymatlar ro'yxatini tuzing).
O'rta¶
4-mashq. bosh_harf(matn) funksiyasi satrning birinchi harfini katta qiladi; bo'sh satrga
ValueError ko'taradi. Maxsus va chegara holatlarini tanlang (bo'sh, bitta belgi, juda uzun satr) va
to'liq parametrize test yozing.
5-mashq. 3-mashqdagi baho(ball) funksiyasini yozing, so'ng parametrize bilan to'liq test
to'plamini tuzing (chegaralar: -1, 0, 59, 60, 100, 101). Hammasi o'tishini tasdiqlang.
6-mashq. xush_kelibsiz(foydalanuvchi, xabarchi) funksiyasi xabarchi.yubor(...) ni chaqiradi.
Mock ishlatib, xulq testini yozing: yubor aynan to'g'ri argumentlar bilan bir marta
chaqirilganini tasdiqlang.
Qiyin¶
7-mashq. 5-mashqdagi baho funksiyasiga off-by-one xato kiriting (masalan, ball >= 60
o'rniga ball > 60). Sizning test to'plamingiz buni tutadimi? Qaysi chegara holati uni tutadi?
Tutmasa β qaysi holatni qo'shish kerak edi?
8-mashq. pul_qaytim(narx, berilgan) funksiyasi berilgan - narx ni qaytaradi; berilgan < narx
bo'lsa ValueError. Funksiyani yozing va test to'plamini tuzing. Diqqat: kasr pul bilan (narx=0.1,
berilgan=0.3) ishlaganda qaytim qanday tekshiriladi? Float tuzog'ini hisobga oling.
Yechimlar
1-mashq yechimi¶
Kompyuter float sonlarni ikkilik (binary) shaklda saqlaydi va 0.1, 0.2 ni aniq ifodalay
olmaydi β kichik xato to'planadi, natijada 0.1 + 0.2 aslida 0.30000000000000004 bo'ladi. Shuning
uchun == 0.3 False qaytaradi. Yechim β pytest.approx, u kichik bardoshlilik bilan
solishtiradi: assert 0.1 + 0.2 == pytest.approx(0.3). Sababi: float arifmetikasida aniq tenglik
deyarli hech qachon mos kelmaydi.
2-mashq yechimi¶
import pytest
def kvadrat_ildiz(x):
if x < 0:
raise ValueError("manfiy sondan ildiz chiqarib bo'lmaydi")
return x ** 0.5
def test_musbat_son():
assert kvadrat_ildiz(9) == 3
def test_manfiy_son_xato():
with pytest.raises(ValueError, match="manfiy"):
kvadrat_ildiz(-4)
# -> 2 passed
3-mashq yechimi¶
Ekvivalentlik sinflari:
1. Past xato: ball < 0
2. Yiqildi: 0β59
3. O'tdi: 60β100
4. Yuqori xato: ball > 100
Tanlangan qiymatlar (vakil + chegaralar):
-1 (past xato chegarasi), 0 (yiqildi quyi cheti), 30 (yiqildi vakili), 59 (yiqildi yuqori cheti),
60 (o'tdi quyi cheti), 100 (o'tdi yuqori cheti), 101 (yuqori xato chegarasi).
4-mashq yechimi¶
import pytest
def bosh_harf(matn):
if not matn:
raise ValueError("bo'sh satr berib bo'lmaydi")
return matn[0].upper() + matn[1:]
@pytest.mark.parametrize("kirish, kutilgan", [
("olim", "Olim"), # happy path
("a", "A"), # chegara: bitta belgi
("olma daraxti", "Olma daraxti"), # bo'sh joy bilan
])
def test_bosh_harf(kirish, kutilgan):
assert bosh_harf(kirish) == kutilgan
def test_bosh_satr_xato():
with pytest.raises(ValueError):
bosh_harf("")
def test_juda_uzun_satr():
natija = bosh_harf("x" * 100000)
assert natija[0] == "X"
assert len(natija) == 100000
# -> 5 passed
5-mashq yechimi¶
import pytest
def baho(ball):
if ball < 0 or ball > 100:
raise ValueError("ball 0..100 oralig'ida bo'lishi kerak")
if ball <= 59:
return "yiqildi"
return "o'tdi"
@pytest.mark.parametrize("ball, kutilgan", [
(0, "yiqildi"),
(59, "yiqildi"),
(60, "o'tdi"),
(100, "o'tdi"),
])
def test_baho_ijobiy(ball, kutilgan):
assert baho(ball) == kutilgan
@pytest.mark.parametrize("ball", [-1, 101])
def test_baho_xato(ball):
with pytest.raises(ValueError):
baho(ball)
# -> 6 passed
6-mashq yechimi¶
from unittest.mock import Mock
def xush_kelibsiz(foydalanuvchi, xabarchi):
xabarchi.yubor(foydalanuvchi, "Xush kelibsiz!")
def test_xush_kelibsiz_yuboradi():
soxta = Mock()
xush_kelibsiz("Olim", soxta)
soxta.yubor.assert_called_once_with("Olim", "Xush kelibsiz!")
# -> 1 passed
assert_called_once_with ikki narsani birga tekshiradi: chaqiruv bir marta bo'lgani va
argumentlar aynan mos kelgani. Bu β xulq (behavior) tekshirish.
7-mashq yechimi¶
Mantiqni if ball > 60: return "o'tdi" deb yozsak, baho(60) "o'tdi" o'rniga "yiqildi"
qaytaradi β chunki 60 > 60 False. Bizning to'plamdagi (60, "o'tdi") chegara holati aynan
shu xatoni tutadi:
Agar to'plamda 60 chegara holati bo'lmaganida (masalan, faqat 30 va 90 ni sinaganimizda), bu
off-by-one xato yashirin qolardi. Saboq: sinflar tutashgan aniq nuqtani (59/60) test qilish
shart.
8-mashq yechimi¶
import pytest
def pul_qaytim(narx, berilgan):
if berilgan < narx:
raise ValueError("berilgan pul narxdan kam")
return berilgan - narx
def test_oddiy_qaytim():
assert pul_qaytim(70, 100) == 30
def test_aniq_pul():
assert pul_qaytim(100, 100) == 0 # chegara: teng
def test_kam_pul_xato():
with pytest.raises(ValueError, match="kam"):
pul_qaytim(100, 70)
def test_kasr_pul_approx():
# Float tuzog'i: 0.3 - 0.1 aniq 0.2 emas!
assert pul_qaytim(0.1, 0.3) == pytest.approx(0.2)
# -> 4 passed
Kasr pul bilan 0.3 - 0.1 aslida 0.19999999999999998 bo'ladi, shuning uchun == 0.2 yiqiladi β
pytest.approx shart. Chegara holati berilgan == narx (qaytim 0) ni ham qo'shdik.
π README Β· β¬ οΈ Oldingi: 04 β Yaxshi test xossalari Β· Keyingi: 06 β Fixture va parametrize β‘οΈ