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.

🕑 12 daqiqa o‘qish 📄 966 so‘z 👁 0 marta ko‘rilgan
Ushbu bo‘lim mundarijasi
  1. Uchta daraja
  2. Modul testi
  3. Integratsiya testi
  4. Uchidan-uchiga test
  5. Endi uchalasini o'lchaymiz
  6. Qarshi-naqsh: muzqaymoq shoxi
  7. Nimani testlash kerak emas
  8. Xulosa

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 #

Test piramidasi E2E Integratsiya Modul (birlik) testlari Kam sekin, qimmat O'rtacha haqiqiy bog'lanish Ko'p tez, arzon sekin tez Pastga tushgan sari testlar tezlashadi va arzonlashadi - shuning uchun ular ko'p bo'ladi
Shakl tasodifiy emas: eng ko'p test eng pastda bo'lishi kerak
DarajaNimani tekshiradiTezligiYiqilganda
ModulBitta funksiya yoki sinf, ajratilgan holdaMillisoniyaXato joyi darhol ma'lum
IntegratsiyaIkki-uch qismning birgalikda ishlashiSoniyaning o'ndan biriQaysi qismda ekani noaniq
E2EButun tizim, foydalanuvchi ko'zi bilanSoniya yoki daqiqaXato 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:

Python
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)
Python
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:

Python
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
Python
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:

Python
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()
Python
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:

Terminal
pytest -q test_modul.py
Natija
...                                                              [100%]
3 passed in 0.01s

Endi bitta integratsiya testi:

Terminal
pytest -q test_integratsiya.py
Natija
.                                                                [100%]
1 passed in 0.03s

Va bitta E2E testi:

Terminal
pytest -q test_uchidan.py
Natija
.                                                                [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:

Terminal
pytest -q --durations=3
Natija
.....                                                            [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.

Nima uchun aynan piramida

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.

To'g'ri: piramida Noto'g'ri: muzqaymoq shoxi ko'p modul testi ko'p E2E testi Tez ishlaydi, xato joyi aniq Har kommitda ishga tushiriladi Sekin, beqaror, qimmat Asta-sekin o'chirib tashlanadi Teskari shakl odatda "keyinroq test yozamiz" qaroridan kelib chiqadi
Muzqaymoq shoxi - piramidaning ag'darilgan ko'rinishi

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.

Piramidani raqam sifatida emas, yo'nalish sifatida oling

"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:

TestlamangSababi
Tilning o'zini (len, sorted)Uni Python jamoasi testlagan
Tashqi kutubxonalarniUlarning o'z testlari bor
Oddiy get/set metodlariniUlarda mantiq yo'q, sinadigan narsa yo'q
Yopiq (_privat) metodlarniOchiq interfeys orqali tekshiring
Aniq tasodifiy chiqishniFaqat uning xossalarini tekshiring
Ekrandagi ranglar va piksellarniHar dizayn o'zgarishida yiqiladi
Yozib bo'lingan, o'zgarmaydigan eski kodniFoyda kamroq - 16-bo'limga qarang

Buning o'rniga nimani testlash kerak:

TestlangSababi
Chegara qiymatlarini0, -1, bo'sh ro'yxat, juda katta son
Xato yo'llariniKo'pincha ular hech qachon ishga tushirilmagan
Biznes qoidalariniAynan ular pul va obro'ga ta'sir qiladi
Tuzatilgan nosozliklarniQaytib kelmasligi uchun
Ko'p ishlatiladigan yo'lniSinsa, hamma sezadi
Qaysi darajani tanlashning oddiy mezoni

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.

Amaliy topshiriq
  1. Uchta test faylini yozib, har birini alohida ishga tushiring va vaqtlarni yozib oling.
  2. O'z kompyuteringizdagi vaqtlarni yozib oling va darslikdagi bilan solishtiring.
  3. Uchta daraja orasidagi farq necha baravar chiqdi?
  4. soliq() funksiyasiga manfiy maosh uchun test qo'shing.
  5. Integratsiya testiga uchinchi xodim qo'shing va kutilgan summani hisoblang.
  6. E2E testda noto'g'ri formatdagi kirish bering - dastur qanday xato beradi?
  7. Ishlayotgan loyihangizdagi testlarni uch darajaga ajratib sanang.
  8. Natija piramidagami yoki muzqaymoq shoxigami - yozib qo'ying.
  9. "Testlamang" jadvalidan loyihangizda uchraydigan bittasini toping.
  10. 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=N eng 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/set larni 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.

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.