4-bo‘lim
Test piramidasi - nimani va qaysi darajada testlash
Modul, integratsiya va uchidan-uchiga testlar farqi, ularning haqiqiy tezligi, muzqaymoq shoxi qarshi-naqshi va umuman testlash kerak bo'lmagan narsalar.
Ushbu bo‘lim mundarijasi
Oldingi bo'limlarda bitta funksiyani tekshirdik. Haqiqiy dasturda esa o'nlab modul, ma'lumotlar bazasi, tarmoq va foydalanuvchi interfeysi bor.
Savol tug'iladi: qaysi birini testlash kerak? Javob - hammasini, lekin har xil miqdorda.
Uchta daraja #
| Daraja | Nimani tekshiradi | Tezligi | Yiqilganda |
|---|---|---|---|
| Modul | Bitta funksiya yoki sinf, ajratilgan holda | Millisoniya | Xato joyi darhol ma'lum |
| Integratsiya | Ikki-uch qismning birgalikda ishlashi | Soniyaning o'ndan biri | Qaysi qismda ekani noaniq |
| E2E | Butun tizim, foydalanuvchi ko'zi bilan | Soniya yoki daqiqa | Xato joyini qidirish kerak |
Bu farqni gapirish emas, o'lchash kerak. Uchta darajaga bittadan test yozib, vaqtini taqqoslaymiz.
Modul testi #
Eng past daraja - toza funksiya, hech narsaga bog'liq emas:
def soliq(maosh):
"""Oylik maoshdan olinadigan daromad solig'i (12%)."""
if maosh < 0:
raise ValueError("maosh manfiy bo'lishi mumkin emas")
return round(maosh * 0.12)
from soliq import soliq
def test_oddiy_maosh():
assert soliq(5_000_000) == 600_000
def test_nol_maosh():
assert soliq(0) == 0
def test_yumaloqlash():
assert soliq(1_000_001) == 120_000
Integratsiya testi #
Endi ma'lumotlar bazasi qo'shiladi - kod endi yolg'iz emas:
import sqlite3
from soliq import soliq
def hisobot_yoz(baza_yoli, xodimlar):
"""Xodimlar ro'yxatini bazaga yozadi va jami soliqni qaytaradi."""
ulanish = sqlite3.connect(baza_yoli)
ulanish.execute(
"CREATE TABLE IF NOT EXISTS xodim (ism TEXT, maosh INTEGER, soliq INTEGER)"
)
jami = 0
for ism, maosh in xodimlar:
summa = soliq(maosh)
jami += summa
ulanish.execute("INSERT INTO xodim VALUES (?, ?, ?)", (ism, maosh, summa))
ulanish.commit()
ulanish.close()
return jami
import sqlite3
from ombor import hisobot_yoz
def test_baza_toldiriladi(tmp_path):
baza = tmp_path / "hisobot.db"
xodimlar = [("Aziza", 5_000_000), ("Bekzod", 7_000_000)]
jami = hisobot_yoz(str(baza), xodimlar)
assert jami == 1_440_000
ulanish = sqlite3.connect(str(baza))
qatorlar = ulanish.execute("SELECT ism, soliq FROM xodim").fetchall()
ulanish.close()
assert qatorlar == [("Aziza", 600_000), ("Bekzod", 840_000)]
tmp_path - pytest ning tayyor yordamchisi: har test uchun vaqtinchalik
papka beradi va keyin o'zi tozalaydi. 7-bo'limda batafsil ko'ramiz.
Uchidan-uchiga test #
Eng yuqori daraja - dasturni foydalanuvchi qanday ishga tushirsa, shunday ishga tushirish:
import sys
from ombor import hisobot_yoz
def main():
baza = sys.argv[1]
xodimlar = []
for qator in sys.stdin:
ism, maosh = qator.strip().split(",")
xodimlar.append((ism, int(maosh)))
print(f"jami soliq: {hisobot_yoz(baza, xodimlar)}")
if __name__ == "__main__":
main()
import subprocess
import sys
def test_dastur_toliq_ishlaydi(tmp_path):
baza = tmp_path / "hisobot.db"
kirish = "Aziza,5000000\nBekzod,7000000\n"
natija = subprocess.run(
[sys.executable, "asosiy.py", str(baza)],
input=kirish, capture_output=True, text=True,
)
assert natija.returncode == 0
assert natija.stdout.strip() == "jami soliq: 1440000"
Endi uchalasini o'lchaymiz #
Har bir faylni alohida ishga tushirib, oxirgi qatordagi vaqtni solishtiramiz. Avval uchta modul testi:
pytest -q test_modul.py
... [100%]
3 passed in 0.01s
Endi bitta integratsiya testi:
pytest -q test_integratsiya.py
. [100%]
1 passed in 0.03s
Va bitta E2E testi:
pytest -q test_uchidan.py
. [100%]
1 passed in 0.04s
Uchta modul testi birgalikda eng tez; bitta integratsiya testi ulardan sezilarli sekin; E2E testi esa eng sekin - garchi u ham xuddi shu hisob-kitobni bajarsa ham. Farq hisobda emas, atrofdagi ishda: fayl ochish, jarayon ishga tushirish, Python ni qaytadan yuklash.
Qaysi test qancha vaqt olganini bitta ro'yxatda ko'rish uchun
--durations bayrog'i bor:
pytest -q --durations=3
..... [100%]
========================= slowest 3 durations ==========================
0.04s call test_uchidan.py::test_dastur_toliq_ishlaydi
0.02s call test_integratsiya.py::test_baza_toldiriladi
(1 durations < 0.005s hidden. Use -vv to show these durations.)
5 passed in 0.07s
Va bu - juda kichkina misol: haqiqiy E2E testda brauzer ochiladi, server ko'tariladi, ma'lumot tarmoq orqali yuriladi. U yerda farq yuz baravargacha yetadi.
Faraz qiling, sizda 1000 ta test bor va ularning hammasi E2E. Har biri 5 soniya - jami 83 daqiqa. Hech kim buni har kommitda ishga tushirmaydi.
Endi 900 tasi modul testi (har biri 1 ms), 90 tasi integratsiya (100 ms) va 10 tasi E2E (5 soniya) bo'lsin. Jami: 0.9 + 9 + 50 = 60 soniya.
Bir xil ishonch, lekin 80 baravar tez. Piramida shakli aynan shu hisobdan kelib chiqqan.
Qarshi-naqsh: muzqaymoq shoxi #
Amalda jamoalar ko'pincha teskari shaklga kelib qoladi.
Bu shakl odatda shunday paydo bo'ladi: dastur testsiz yoziladi, keyin sifat bo'limi tashqaridan E2E testlar qo'shadi. Ular sekin va beqaror bo'lgani uchun asta-sekin o'chiriladi - va oxirida hech narsa qolmaydi.
"70% modul, 20% integratsiya, 10% E2E" degan raqamlar internetda ko'p uchraydi. Ular o'ylab topilgan - hech qanday tadqiqot ularni tasdiqlamagan.
To'g'ri o'qish shunday: xatoni eng past darajada tuta oladigan test yozing. Agar xatoni modul testi tuta olsa - E2E yozmang. Agar faqat qismlar orasidagi bog'lanishda xato bo'lishi mumkin bo'lsa - integratsiya testi yozing.
Bunday yondashuvda piramida o'zi paydo bo'ladi, sanashning hojati qolmaydi.
Nimani testlash kerak emas #
Bu ro'yxat testlar sonini kamaytiradi va qolganlarini foydaliroq qiladi:
| Testlamang | Sababi |
|---|---|
Tilning o'zini (len, sorted) | Uni Python jamoasi testlagan |
| Tashqi kutubxonalarni | Ularning o'z testlari bor |
Oddiy get/set metodlarini | Ularda mantiq yo'q, sinadigan narsa yo'q |
Yopiq (_privat) metodlarni | Ochiq interfeys orqali tekshiring |
| Aniq tasodifiy chiqishni | Faqat uning xossalarini tekshiring |
| Ekrandagi ranglar va piksellarni | Har dizayn o'zgarishida yiqiladi |
| Yozib bo'lingan, o'zgarmaydigan eski kodni | Foyda kamroq - 16-bo'limga qarang |
Buning o'rniga nimani testlash kerak:
| Testlang | Sababi |
|---|---|
| Chegara qiymatlarini | 0, -1, bo'sh ro'yxat, juda katta son |
| Xato yo'llarini | Ko'pincha ular hech qachon ishga tushirilmagan |
| Biznes qoidalarini | Aynan ular pul va obro'ga ta'sir qiladi |
| Tuzatilgan nosozliklarni | Qaytib kelmasligi uchun |
| Ko'p ishlatiladigan yo'lni | Sinsa, hamma sezadi |
O'zingizdan so'rang: "bu xato qayerda tug'iladi?"
- Hisob-kitobda xato bo'lsa - modul testi.
- SQL so'rovi noto'g'ri yozilgan bo'lsa - integratsiya testi.
- Tugma ishlamasa yoki sahifa ochilmasa - E2E testi.
Bitta xatoni uch darajada ham tekshirish - ortiqcha ish. Uni eng past darajada tuting.
- Uchta test faylini yozib, har birini alohida ishga tushiring va vaqtlarni yozib oling.
- O'z kompyuteringizdagi vaqtlarni yozib oling va darslikdagi bilan solishtiring.
- Uchta daraja orasidagi farq necha baravar chiqdi?
soliq()funksiyasiga manfiy maosh uchun test qo'shing.- Integratsiya testiga uchinchi xodim qo'shing va kutilgan summani hisoblang.
- E2E testda noto'g'ri formatdagi kirish bering - dastur qanday xato beradi?
- Ishlayotgan loyihangizdagi testlarni uch darajaga ajratib sanang.
- Natija piramidagami yoki muzqaymoq shoxigami - yozib qo'ying.
- "Testlamang" jadvalidan loyihangizda uchraydigan bittasini toping.
- Oxirgi tuzatgan nosozligingiz qaysi darajadagi test bilan tutilishi mumkin edi?
Xulosa #
- Testlar uch darajaga bo'linadi: modul, integratsiya va uchidan-uchiga (E2E).
- Modul testi bitta funksiyani ajratilgan holda tekshiradi va millisoniyalarda ishlaydi.
- Integratsiya testi bir necha qismning birgalikda ishlashini - masalan kod va ma'lumotlar bazasini - tekshiradi.
- E2E testi dasturni foydalanuvchi ishlatganidek, tashqaridan ishga tushiradi.
- Pastdan yuqoriga qarab test sekinlashadi, qimmatlashadi va yiqilganda xato joyini topish qiyinlashadi.
- Shuning uchun eng ko'p test eng past darajada bo'ladi - bu shakl test piramidasi deb ataladi.
pytest --durations=Neng sekin N ta testni ro'yxat qilib beradi - farqni o'zingiz o'lchashingiz mumkin.- Muzqaymoq shoxi - teskari shakl: ko'p E2E, kam modul testi; u sekin va beqaror bo'ladi.
- Piramidadagi foizlar o'ylab topilgan; to'g'ri qoida - xatoni eng past darajada tutish.
- Tilning o'zini, tashqi kutubxonalarni, oddiy
get/setlarni va yopiq metodlarni testlash kerak emas. - Testlash kerak: chegara qiymatlari, xato yo'llari, biznes qoidalari va tuzatilgan nosozliklar.
tmp_path- pytest ning tayyor yordamchisi: har test uchun vaqtinchalik papka beradi va o'zi tozalaydi.
Keyingi bo'limda bitta testning ichiga qaraymiz: yaxshi test qanday tuzilgan bo'ladi va uni qanday nomlash kerak.
O‘qish tarixini saqlamoqchimisiz?
Tizimga kirsangiz, tugatgan bo‘limlaringiz saqlanadi va qoldirgan joyingizdan davom etasiz.
Xatolik topdingizmi?
Imlo xatosi, ishlamaydigan kod yoki noto‘g‘ri ma‘lumotni ko‘rsangiz - bizga xabar bering. Har bir xabar administrator tomonidan ko‘rib chiqiladi.