Mundarija (22)
- 1. Kirish va motivatsiya
- 2. Nazariya — chuqur tushuntirish
- 2.1. Coverage nima o'lchaydi
- 2.2. coverage run va report
- 2.3. Ko'r nuqtalarni topish
- 2.4. Tarmoqlanish qamrovi (branch coverage)
- 2.5. pytest-cov va sozlash
- 2.6. Qatorlarni chiqarib tashlash
- 2.7. Coverage ni to'g'ri talqin qilish
- 2.8. Qancha coverage kerak
- 3. Tez ma'lumotnoma
- 4. Batafsil misollar
- Misol 1 — Coverage o'lchash va ko'r nuqtalar
- Misol 2 — Statement vs branch coverage
- Misol 3 — 100% coverage ≠ xatosiz kod
- Misol 4 — Amaliy: ko'r nuqtalarni topib yopish
- 5. To'g'ri va noto'g'ri tushunishlar
- 6. Keng tarqalgan xatolar va yechimlari
- 7. Integratsiya — bu bilim qayerda kerak bo'ladi
- 8. Eng yaxshi amaliyotlar
- 9. Amaliy topshiriq
- Xulosa
17.7-dars: Coverage
17-QISM — TESTLASH · 7-dars
1. Kirish va motivatsiya
Testlar yozdik — lekin ular kodning qancha qismini tekshiradi? Ba'zi funksiyalar, shartlar, xato yo'llari umuman test qilinmagan bo'lishi mumkin. Coverage (qamrov) — testlar kodning qaysi qatorlarini ishga tushirganini o'lchaydigan vosita. U test qilinmagan qatorlarni ko'rsatadi — ya'ni "ko'r nuqtalar" ni.
Coverage foydali, lekin xavfli ham: yuqori foizni "kod xatosiz" deb tushunish mumkin. Aslida coverage faqat qator ishga tushirilganini aytadi, u to'g'ri ishlaganini emas. Bu farqni tushunish — coverage ni to'g'ri ishlatishning kaliti.
Real vaziyat. Bir jamoa "90% coverage" maqsadini qo'ydi va unga yetdi — lekin ishlab chiqarishda hali ham xatolar chiqardi. Tekshirishda ma'lum bo'ldiki, testlar kodni ishga tushirar, lekin natijani jiddiy tekshirmasdi: funksiya(x) chaqirilar, lekin assert yo'q edi. Coverage 90% ko'rsatardi, chunki qatorlar bajarilardi — lekin xatolarni ushlamas edi. Boshqa tomondan, ular coverage hisobotida eng muhim funksiyaning xato yo'li (istisno) umuman test qilinmaganini ko'rishdi — coverage aynan shu ko'r nuqtani topib berdi. Coverage vositasi emas, uni qanday talqin qilish muhim ekan.
Bu darsda coverage ni o'lchashni, ko'r nuqtalarni topishni va foizni to'g'ri talqin qilishni o'rganamiz.
Bu darsda:
- Coverage nima va nima o'lchaydi
coverage runvacoverage report- Test qilinmagan qatorlarni topish (
missing) - Tarmoqlanish qamrovi (branch coverage)
pytest-covva sozlash- Qatorlarni chiqarib tashlash (
pragma: no cover) - 100% coverage ≠ xatosiz kod
- Amaliy: ko'r nuqtalarni topib yopish
ℹ Bu darsda
coverage— tashqi kutubxona (pip install coverage) ishlatiladi.
2. Nazariya — chuqur tushuntirish
2.1. Coverage nima o'lchaydi
Coverage — testlar bajarilganda kodning qaysi qatorlari ishga tushganini yozib boradi:
| Metrika | Ma'nosi |
|---|---|
| Statement coverage | Necha qator (bayonot) bajarildi |
| Branch coverage | Har shart (if) ikkala tomoni tekshirildimi |
Miss |
Bajarilmagan qatorlar |
Cover |
Foiz (bajarilgan / jami) |
Coverage faqat qator bajarilganini o'lchaydi, to'g'ri ishlaganini emas — bu muhim farq.
2.2. coverage run va report
coverage run -m pytest # testlarni coverage kuzatuvida ishga tushiradi
coverage report -m # hisobot + qaysi qatorlar qamralmagan (-m = missing)
coverage html # brauzerda ko'riladigan batafsil hisobotNamunaviy hisobot:
Name Stmts Miss Cover Missing
-------------------------------------------
kod.py 10 3 70% 5, 7, 11 Missing ustuni — aynan qaysi qatorlar test qilinmaganini ko'rsatadi (bu yerda 5, 7, 11-qatorlar).
2.3. Ko'r nuqtalarni topish
Coverage ning eng qimmatli imkoniyati — test qilinmagan qatorlarni ko'rsatish. Ko'pincha bular:
| Ko'r nuqta | Sabab |
|---|---|
Xato yo'llari (except, raise) |
"Baxtli yo'l" test qilinadi, xato yo'li unutiladi |
| Chegara shartlari | Kam uchraydigan if shohobchalari |
| Kam ishlatiladigan funksiyalar | Yozilgan, lekin test qilinmagan |
| Himoya shartlari | "Bu hech qachon bo'lmaydi" degan kod |
Coverage bu nuqtalarni topib, qaysi testlar yetishmayotganini aniq ko'rsatadi.
2.4. Tarmoqlanish qamrovi (branch coverage)
Oddiy statement coverage if x: qatorini bajarilgan deb belgilaydi — lekin x False bo'lgan holat test qilinmagan bo'lishi mumkin. Branch coverage ikkala tomonni ham talab qiladi:
coverage run --branch -m pytestName Stmts Miss Branch BrPart Cover
kod.py 10 3 6 2 69% Branch — jami tarmoqlanishlar, BrPart — qisman qamralgan (faqat bir tomoni). Branch coverage statement coverage dan qattiqroq va ishonchliroq.
2.5. pytest-cov va sozlash
pytest-cov plagini coverage ni to'g'ridan-to'g'ri pytest ga qo'shadi:
pytest --cov=mening_paket --cov-report=term-missingSozlash pyproject.toml da:
[tool.coverage.run]
branch = true
source = ["mening_paket"]
[tool.coverage.report]
show_missing = true
fail_under = 80 # 80% dan past bo'lsa xato (CI uchun) fail_under — CI/CD (28-qism) da minimal qamrovni majburiy qiladi.
2.6. Qatorlarni chiqarib tashlash
Ba'zi qatorlarni (masalan if __name__ == "__main__", mudofaa kodi) qamrovdan chiqarish:
def himoya():
if holat_bolmaydi: # pragma: no cover
raise RuntimeError("bu hech qachon bo'lmasligi kerak") # pragma: no cover ni ehtiyotkorlik bilan — u qamrovni "yasama" oshirishi mumkin. Faqat haqiqatan test qilib bo'lmaydigan kod uchun.
2.7. Coverage ni to'g'ri talqin qilish
| Noto'g'ri fikr | To'g'ri talqin |
|---|---|
| "100% coverage = xatosiz" | Faqat qator bajarilgan, natija tekshirilmagan bo'lishi mumkin |
| "Yuqori foiz — asosiy maqsad" | Ma'noli testlar muhimroq |
| "Coverage past — yomon kod" | Muhim qismlar qamralgani muhimroq |
| "Foizni oshirish uchun test yozish" | Ko'r nuqtalarni ma'noli yopish |
Coverage — ko'r nuqtalarni topish vositasi, sifat metrikasi emas. assert siz test coverage ni oshiradi, lekin xato ushlamaydi.
2.8. Qancha coverage kerak
| Kod turi | Maqsad |
|---|---|
| Biznes mantiq (kritik) | Yuqori (90%+), ma'noli |
| Yordamchi kod | O'rtacha |
| Prototip/skript | Kam yoki umuman yo'q |
100% ni maqsad qilish ko'pincha samarasiz: oxirgi 5-10% ba'zan test qilib bo'lmaydigan yoki arzimas kod. Muhim yo'llarni to'liq, ma'noli qamrash — foizni quvishdan yaxshiroq.
3. Tez ma'lumotnoma
coverage run -m pytest # coverage bilan test
coverage report -m # hisobot + missing qatorlar
coverage run --branch -m pytest # tarmoqlanish qamrovi
coverage html # batafsil HTML hisobot
pytest --cov=paket --cov-report=term-missing # pytest-cov bilan# pyproject.toml
[tool.coverage.run]
branch = true
source = ["paket"]
[tool.coverage.report]
show_missing = true
fail_under = 80Qoidalar
coverage — ko'r nuqtalarni topish vositasi
missing ustuni — test qilinmagan qatorlar
branch coverage — statement dan ishonchliroq
100% coverage ≠ xatosiz (assert siz oshadi)
xato yo'llarini (except) qamrang — ko'p unutiladi
foizni quvma — muhim yo'llarni ma'noli qamra
pragma: no cover — ehtiyotkorlik bilan4. Batafsil misollar
Misollarda
coverageni deterministik ishga tushiruvchicoverage_olyordamchisi ishlatiladi.
Misol 1 — Coverage o'lchash va ko'r nuqtalar
"""coverage run + report; missing qatorlar test qilinmagan kodni ko'rsatadi; xato yo'li (except) qamralmagani aniqlanadi; test qo'shib yopish."""
import json
import subprocess
import sys
import tempfile
from pathlib import Path
def coverage_ol(katalog: Path, *args: str) -> dict:
"""coverage run + json; deterministik ma'lumot qaytaradi."""
subprocess.run([sys.executable, "-m", "coverage", "run", *args, "-m", "pytest",
"-p", "no:cacheprovider", "-o", "addopts=", "-q"],
cwd=katalog, capture_output=True, text=True, encoding="utf-8")
r = subprocess.run([sys.executable, "-m", "coverage", "json", "-o", "-"],
cwd=katalog, capture_output=True, text=True, encoding="utf-8")
return json.loads(r.stdout)
KOD = '''
def toifala(son):
if son < 0:
return "manfiy"
if son == 0:
return "nol"
if son > 100:
return "katta"
return "oddiy"
def xavfsiz_bol(a, b):
if b == 0:
raise ValueError("nolga bo'lib bo'lmaydi")
return a / b
'''
def main() -> None:
with tempfile.TemporaryDirectory() as katalog:
r = Path(katalog)
(r / "kod.py").write_text(KOD, encoding="utf-8")
print("=== 1. Kam test — ko'r nuqtalar ko'p ===")
(r / "test_kod.py").write_text(
"from kod import toifala, xavfsiz_bol\n"
"def test_manfiy(): assert toifala(-1) == 'manfiy'\n"
"def test_oddiy(): assert toifala(50) == 'oddiy'\n"
"def test_bol(): assert xavfsiz_bol(6, 2) == 3\n", encoding="utf-8")
d = coverage_ol(r)
fayl = d["files"]["kod.py"]
print(f" qamrov: {fayl['summary']['percent_covered_display']}%")
print(f" test qilinmagan qatorlar: {fayl['missing_lines']}")
print(" ⚠️ 'nol', 'katta' shohobchalari va nolga bo'lish xatosi qamralmagan")
print("\n=== 2. Ko'r nuqtalarni yopish ===")
(r / "test_kod.py").write_text(
"import pytest\n"
"from kod import toifala, xavfsiz_bol\n"
"def test_manfiy(): assert toifala(-1) == 'manfiy'\n"
"def test_nol(): assert toifala(0) == 'nol'\n"
"def test_katta(): assert toifala(200) == 'katta'\n"
"def test_oddiy(): assert toifala(50) == 'oddiy'\n"
"def test_bol(): assert xavfsiz_bol(6, 2) == 3\n"
"def test_bol_nol():\n"
" with pytest.raises(ValueError):\n"
" xavfsiz_bol(1, 0)\n", encoding="utf-8")
d = coverage_ol(r)
fayl = d["files"]["kod.py"]
print(f" qamrov: {fayl['summary']['percent_covered_display']}%")
print(f" test qilinmagan qatorlar: {fayl['missing_lines'] or 'yo`q — hammasi qamraldi'}")
print(" ⭐ coverage aynan qaysi test yetishmasligini ko'rsatdi")
if __name__ == "__main__":
main()Natijaning muhim qismi:
=== 1. Kam test — ko'r nuqtalar ko'p ===
qamrov: 75%
test qilinmagan qatorlar: [6, 8, 13]
⚠️ 'nol', 'katta' shohobchalari va nolga bo'lish xatosi qamralmagan
=== 2. Ko'r nuqtalarni yopish ===
qamrov: 100%
test qilinmagan qatorlar: yo`q — hammasi qamraldi
⭐ coverage aynan qaysi test yetishmasligini ko'rsatdiNima ko'rsatdi: 2.1, 2.2, 2.3-bo'limlar.
Misol 2 — Statement vs branch coverage
"""statement coverage 100% bo'lsa ham branch qamralmagan bo'lishi mumkin; branch coverage ikkala tomonni talab qiladi; qisman tarmoqlanish (BrPart)."""
import json
import subprocess
import sys
import tempfile
from pathlib import Path
def coverage_ol(katalog: Path, branch: bool) -> dict:
args = ["--branch"] if branch else []
subprocess.run([sys.executable, "-m", "coverage", "run", *args, "-m", "pytest",
"-p", "no:cacheprovider", "-o", "addopts=", "-q"],
cwd=katalog, capture_output=True, text=True, encoding="utf-8")
r = subprocess.run([sys.executable, "-m", "coverage", "json", "-o", "-"],
cwd=katalog, capture_output=True, text=True, encoding="utf-8")
return json.loads(r.stdout)
KOD = '''
def chegirma(narx, vip):
natija = narx
if vip:
natija = narx * 0.9
return natija
'''
# Test faqat vip=True ni sinaydi — 'if' ning False tomoni test qilinmaydi
TEST = '''
from kod import chegirma
def test_vip():
assert chegirma(100, True) == 90
'''
def main() -> None:
with tempfile.TemporaryDirectory() as katalog:
r = Path(katalog)
(r / "kod.py").write_text(KOD, encoding="utf-8")
(r / "test_kod.py").write_text(TEST, encoding="utf-8")
print("=== 1. Statement coverage ===")
d = coverage_ol(r, branch=False)
s = d["files"]["kod.py"]["summary"]
print(f" qamrov: {s['percent_covered_display']}% — barcha qator bajarildi")
print(" ⚠️ lekin vip=False holati test qilinmagan!")
print("\n=== 2. Branch coverage ===")
d = coverage_ol(r, branch=True)
s = d["files"]["kod.py"]["summary"]
print(f" qamrov: {s['percent_covered_display']}%")
print(f" jami tarmoqlanish: {s['num_branches']}, qisman qamralgan: {s['num_partial_branches']}")
print(" ⭐ branch coverage vip=False qamralmaganini ochib berdi")
print("\n=== 3. Ikkala tomonni test qilib ===")
(r / "test_kod.py").write_text(
"from kod import chegirma\n"
"def test_vip(): assert chegirma(100, True) == 90\n"
"def test_oddiy(): assert chegirma(100, False) == 100\n", encoding="utf-8")
d = coverage_ol(r, branch=True)
s = d["files"]["kod.py"]["summary"]
print(f" qamrov: {s['percent_covered_display']}%, qisman qamralgan: {s['num_partial_branches']}")
if __name__ == "__main__":
main()Natijaning muhim qismi:
=== 1. Statement coverage ===
qamrov: 100% — barcha qator bajarildi
⚠️ lekin vip=False holati test qilinmagan!
=== 2. Branch coverage ===
qamrov: 86%
jami tarmoqlanish: 2, qisman qamralgan: 1
⭐ branch coverage vip=False qamralmaganini ochib berdi
=== 3. Ikkala tomonni test qilib ===
qamrov: 100%, qisman qamralgan: 0Nima ko'rsatdi: 2.4-bo'lim.
Misol 3 — 100% coverage ≠ xatosiz kod
"""assert siz test coverage ni oshiradi, lekin xato ushlamaydi; 100% qamrov bilan ham buzuq kod o'tadi; ma'noli test farqi."""
import json
import subprocess
import sys
import tempfile
from pathlib import Path
def coverage_va_test(katalog: Path) -> tuple[dict, int]:
natija = subprocess.run([sys.executable, "-m", "coverage", "run", "-m", "pytest",
"-p", "no:cacheprovider", "-o", "addopts=", "-q"],
cwd=katalog, capture_output=True, text=True, encoding="utf-8")
r = subprocess.run([sys.executable, "-m", "coverage", "json", "-o", "-"],
cwd=katalog, capture_output=True, text=True, encoding="utf-8")
return json.loads(r.stdout), natija.returncode
# Kodda XATO bor: qo'shish o'rniga ayirish
KOD = '''
def yakuniy_narx(narx, chegirma):
return narx - chegirma / 100 # XATO: bu narxni deyarli o'zgartirmaydi
'''
# "Yomon" test: chaqiradi, lekin natijani JIDDIY tekshirmaydi
YOMON_TEST = '''
from kod import yakuniy_narx
def test_ishlaydi():
natija = yakuniy_narx(100, 20)
assert natija is not None # ⚠️ faqat "None emas" — xatoni ushlamaydi
'''
# "Yaxshi" test: aniq natijani tekshiradi
YAXSHI_TEST = '''
from kod import yakuniy_narx
def test_chegirma():
assert yakuniy_narx(100, 20) == 80 # aniq qiymat — xatoni ushlaydi
'''
def main() -> None:
with tempfile.TemporaryDirectory() as katalog:
r = Path(katalog)
(r / "kod.py").write_text(KOD, encoding="utf-8")
print("=== 1. 'Yomon' test — 100% coverage, lekin xato o'tadi ===")
(r / "test_kod.py").write_text(YOMON_TEST, encoding="utf-8")
d, kod = coverage_va_test(r)
print(f" qamrov: {d['files']['kod.py']['summary']['percent_covered_display']}%")
print(f" test natijasi: {'o`tdi' if kod == 0 else 'yiqildi'}")
print(" ⚠️ 100% qamrov, lekin buzuq kod o'tib ketdi (assert is not None yetarli emas)")
print("\n=== 2. 'Yaxshi' test — xatoni ushlaydi ===")
(r / "test_kod.py").write_text(YAXSHI_TEST, encoding="utf-8")
d, kod = coverage_va_test(r)
print(f" qamrov: {d['files']['kod.py']['summary']['percent_covered_display']}%")
print(f" test natijasi: {'o`tdi' if kod == 0 else 'yiqildi (xato ushlandi!)'}")
print(" ⭐ bir xil coverage, lekin ma'noli assert xatoni topdi")
print("\n=== 3. Xulosa ===")
print(" coverage — qator bajarilganini o'lchaydi, to'g'riligini EMAS")
print(" yuqori coverage + ma'nosiz assert = yolg'on xotirjamlik")
if __name__ == "__main__":
main()Natijaning muhim qismi:
=== 1. 'Yomon' test — 100% coverage, lekin xato o'tadi ===
qamrov: 100%
test natijasi: o`tdi
⚠️ 100% qamrov, lekin buzuq kod o'tib ketdi (assert is not None yetarli emas)
=== 2. 'Yaxshi' test — xatoni ushlaydi ===
qamrov: 100%
test natijasi: yiqildi (xato ushlandi!)
⭐ bir xil coverage, lekin ma'noli assert xatoni topdi
=== 3. Xulosa ===
coverage — qator bajarilganini o'lchaydi, to'g'riligini EMAS
yuqori coverage + ma'nosiz assert = yolg'on xotirjamlikNima ko'rsatdi: 2.7-bo'lim.
Misol 4 — Amaliy: ko'r nuqtalarni topib yopish
Buyurtma holatini boshqaruvchi modulni test qilamiz. Avval mavjud (to'liq bo'lmagan) testlar bilan coverage o'lchaymiz, coverage ko'rsatgan ko'r nuqtalarni (xato yo'llari, chegara holatlari) aniqlaymiz va ularni ma'noli testlar bilan yopamiz. Bu — coverage ni real ish jarayonida ishlatishning namunasi: foizni quvish emas, yetishmayotgan muhim testlarni topish.
"""coverage bilan ko'r nuqtalarni topib, ma'noli test qo'shib yopish: xato yo'llari, chegara holatlari; branch coverage; foizni emas, muhim yo'llarni qamrash."""
import json
import subprocess
import sys
import tempfile
from pathlib import Path
KOD = '''
class BuyurtmaXatosi(Exception):
pass
VALID_HOLATLAR = {"yangi", "tolangan", "yuborildi", "yetkazildi", "bekor"}
OTISHLAR = {
"yangi": {"tolangan", "bekor"},
"tolangan": {"yuborildi", "bekor"},
"yuborildi": {"yetkazildi"},
"yetkazildi": set(),
"bekor": set(),
}
def holatni_ozgartir(joriy, yangi):
if joriy not in VALID_HOLATLAR:
raise BuyurtmaXatosi(f"noma'lum joriy holat: {joriy}")
if yangi not in VALID_HOLATLAR:
raise BuyurtmaXatosi(f"noma'lum yangi holat: {yangi}")
if yangi not in OTISHLAR[joriy]:
raise BuyurtmaXatosi(f"{joriy} dan {yangi} ga o'tib bo'lmaydi")
return yangi
def bekor_qilsa_boladimi(holat):
return holat in {"yangi", "tolangan"}
'''
def coverage_ol(katalog: Path) -> dict:
subprocess.run([sys.executable, "-m", "coverage", "run", "--branch", "-m", "pytest",
"-p", "no:cacheprovider", "-o", "addopts=", "-q"],
cwd=katalog, capture_output=True, text=True, encoding="utf-8")
r = subprocess.run([sys.executable, "-m", "coverage", "json", "-o", "-"],
cwd=katalog, capture_output=True, text=True, encoding="utf-8")
return json.loads(r.stdout)
DASTLABKI_TEST = '''
from buyurtma import holatni_ozgartir
def test_tolash():
assert holatni_ozgartir("yangi", "tolangan") == "tolangan"
def test_yuborish():
assert holatni_ozgartir("tolangan", "yuborildi") == "yuborildi"
'''
TOLIQ_TEST = '''
import pytest
from buyurtma import holatni_ozgartir, bekor_qilsa_boladimi, BuyurtmaXatosi
def test_tolash():
assert holatni_ozgartir("yangi", "tolangan") == "tolangan"
def test_yuborish():
assert holatni_ozgartir("tolangan", "yuborildi") == "yuborildi"
def test_yetkazish():
assert holatni_ozgartir("yuborildi", "yetkazildi") == "yetkazildi"
def test_bekor():
assert holatni_ozgartir("yangi", "bekor") == "bekor"
def test_notogri_joriy_holat():
with pytest.raises(BuyurtmaXatosi, match="joriy holat"):
holatni_ozgartir("nomalum", "tolangan")
def test_notogri_yangi_holat():
with pytest.raises(BuyurtmaXatosi, match="yangi holat"):
holatni_ozgartir("yangi", "nomalum")
def test_ruxsatsiz_otish():
with pytest.raises(BuyurtmaXatosi, match="o'tib bo'lmaydi"):
holatni_ozgartir("yetkazildi", "yangi")
def test_bekor_qilsa_boladi():
assert bekor_qilsa_boladimi("yangi") is True
def test_bekor_qilib_bolmaydi():
assert bekor_qilsa_boladimi("yetkazildi") is False
'''
def main() -> None:
with tempfile.TemporaryDirectory() as katalog:
r = Path(katalog)
(r / "buyurtma.py").write_text(KOD, encoding="utf-8")
print("=== 1. Dastlabki testlar bilan coverage ===")
(r / "test_buyurtma.py").write_text(DASTLABKI_TEST, encoding="utf-8")
d = coverage_ol(r)
s = d["files"]["buyurtma.py"]["summary"]
print(f" qamrov: {s['percent_covered_display']}%")
print(f" test qilinmagan qatorlar: {d['files']['buyurtma.py']['missing_lines']}")
print(f" qisman tarmoqlanish: {s['num_partial_branches']}")
print(" ⚠️ xato yo'llari va bekor_qilsa_boladimi umuman test qilinmagan")
print("\n=== 2. Ko'r nuqtalarni ma'noli test bilan yopgach ===")
(r / "test_buyurtma.py").write_text(TOLIQ_TEST, encoding="utf-8")
d = coverage_ol(r)
s = d["files"]["buyurtma.py"]["summary"]
print(f" qamrov: {s['percent_covered_display']}%")
print(f" test qilinmagan qatorlar: {d['files']['buyurtma.py']['missing_lines'] or 'yo`q'}")
print(f" qisman tarmoqlanish: {s['num_partial_branches']}")
print(" ⭐ har xato yo'li va shohobcha ma'noli assert bilan qamraldi")
if __name__ == "__main__":
main()Natijaning muhim qismi:
=== 1. Dastlabki testlar bilan coverage ===
qamrov: 65%
test qilinmagan qatorlar: [16, 18, 20, 24]
qisman tarmoqlanish: 3
⚠️ xato yo'llari va bekor_qilsa_boladimi umuman test qilinmagan
=== 2. Ko'r nuqtalarni ma'noli test bilan yopgach ===
qamrov: 100%
test qilinmagan qatorlar: yo`q
qisman tarmoqlanish: 0
⭐ har xato yo'li va shohobcha ma'noli assert bilan qamraldiNima ko'rsatdi: 2.3, 2.4, 2.8-bo'limlar.
5. To'g'ri va noto'g'ri tushunishlar
| Noto'g'ri fikr | To'g'risi |
|---|---|
| "100% coverage = xatosiz kod" | Faqat qator bajarilgan, natija tekshirilmagan bo'lishi mumkin |
| "Coverage — sifat metrikasi" | Ko'r nuqtalarni topish vositasi |
| "Statement coverage yetarli" | Branch coverage ishonchliroq |
| "Foiz qancha yuqori — shuncha yaxshi" | Ma'noli testlar muhimroq |
| "Coverage past — kod yomon" | Muhim qismlar qamralgani muhim |
"assert siz test foydasiz" |
To'g'ri — coverage oshiradi, xato ushlamaydi |
"pragma: no cover — qulay" |
Qamrovni yasama oshiradi, ehtiyot bo'ling |
| "Coverage o'zi xatolarni topadi" | Faqat qamralmagan qatorlarni ko'rsatadi |
6. Keng tarqalgan xatolar va yechimlari
1. Coverage ni sifat metrikasi deb bilish
# 100% coverage, lekin assert yo'q # ❌
def test_x(): funksiya(5)
def test_x(): assert funksiya(5) == 10 # ✅ natijani tekshiring2. Faqat "baxtli yo'l" ni test qilish
def test_bol(): assert bol(6, 2) == 3 # ❌ nolga bo'lish qamralmagan
def test_bol_nol(): # ✅ xato yo'lini ham
with pytest.raises(ValueError): bol(1, 0)3. Statement coverage ga ishonish
coverage run -m pytest # ❌ tarmoqlanish ko'rinmaydi
coverage run --branch -m pytest # ✅ ikkala tomon4. pragma: no cover ni suiiste'mol
def muhim(x):
if x < 0: # pragma: no cover # ❌ muhim shartni yashirish
return xato()
# ✅ faqat haqiqatan test qilib bo'lmaydigan kod5. Foizni quvish
# oxirgi 5% uchun ma'nosiz testlar yozish # ❌
# ✅ muhim yo'llarni to'liq qamrash, arzimasni qoldirish6. Coverage ni ko'rmaslik
coverage run -m pytest # ❌ hisobotsiz — foydasiz
coverage report -m # ✅ missing qatorlarni ko'ring7. Test faylini coverage ga qo'shish
[tool.coverage.run]
# source aniqlanmagan → testlar ham hisoblanadi # ❌
source = ["mening_paket"] # ✅ faqat manba kod7. Integratsiya — bu bilim qayerda kerak bo'ladi
- 17.1–17.6-darslar (o'tilgan): testlar — coverage ular qamrovini o'lchaydi
- 17.8-dars: TDD — test avval yozilsa coverage tabiiy yuqori
- 18.6-dars:
pre-commit— coverage tekshiruvi - 28.7–28.8-darslar: CI/CD —
fail_underbilan minimal qamrov - 31-qism: karyera — coverage sifat madaniyatining bir qismi
8. Eng yaxshi amaliyotlar
Coverage ni ko'r nuqtalarni topish uchun ishlating, sifat metrikasi sifatida emas.
missingqatorlarni ko'rib, yetishmayotgan testlarni yozing.Branch coverage (
--branch) ishlating — ishonchliroq.Xato yo'llarini (
except,raise) alohida qamrang — ko'p unutiladi.Yuqori foizni emas, muhim yo'llarni ma'noli qamrashni maqsad qiling.
sourceni aniqlang — faqat manba kodni o'lchang.CI da
fail_underbilan minimal qamrovni majburiy qiling.pragma: no coverni faqat haqiqatan test qilib bo'lmaydigan kodga.
9. Amaliy topshiriq
Vazifa 1: Natijani bashorat qiling
Quyidagi kod va test uchun missing qatorlarni ayting:
# kod.py (qatorlar raqami bilan)
1 def bel(son):
2 if son < 0:
3 return "manfiy"
4 if son == 0:
5 return "nol"
6 return "musbat"
# test.py
def test_manfiy(): assert bel(-1) == "manfiy"
def test_musbat(): assert bel(5) == "musbat"- Qaysi qatorlar bajariladi?
- Qaysi qator
missing? - Statement coverage foizi (6 qatordan)?
test_nol()qo'shilsa, coverage qanday o'zgaradi?
Va tushunchalar:
coverage run -m pytestkeyin qaysi buyruq missing ni ko'rsatadi?--branchnima qo'shadi?assert x is not Nonecoverage ni oshiradimi?- 100% coverage xatosizlikni kafolatlaydimi?
Javoblar
1, 2, 3(manfiy uchun),1, 2, 4, 6(musbat uchun) → 1, 2, 3, 4, 6 bajariladi5-qator(return "nol") —test_nolyo'q5/6 ≈ 83%100%(5-qator ham qamraladi)coverage report -m- Har
ifning ikkala tomonini (True/False) tekshiradi - Ha — qator bajariladi, lekin xatoni ushlamasligi mumkin
- Yo'q — faqat qator bajarilganini ko'rsatadi
Vazifa 2: Xatolarni tuzating
1. def test_narx():
yakuniy_narx(100, 20) # coverage 100%, lekin...
2. # faqat statement coverage
# coverage run -m pytest
3. def test_bol():
assert bol(6, 2) == 3 # nolga bo'lish qamralmagan
4. def muhim_hisob(x):
if x < 0: # pragma: no cover # muhim shart yashirilgan
raise ValueError()
return x * 2
5. [tool.coverage.run]
# source yo'q # testlar ham hisoblanadiJavoblar
1. def test_narx():
assert yakuniy_narx(100, 20) == 80 # natijani tekshiring
2. # branch coverage
# coverage run --branch -m pytest
3. def test_bol():
assert bol(6, 2) == 3
def test_bol_nol(): # xato yo'lini qamrang
with pytest.raises(ValueError):
bol(1, 0)
4. def muhim_hisob(x):
if x < 0: # pragma olib tashlandi
raise ValueError()
return x * 2
# test:
def test_manfiy():
with pytest.raises(ValueError):
muhim_hisob(-1)
5. [tool.coverage.run]
source = ["mening_paket"] # faqat manba kod
branch = trueVazifa 3: Coverage hisobotini tahlil
Bir modul uchun coverage o'lchang va:
coverage report -mvacoverage htmlni solishtiring- Eng past qamrovli funksiyani toping
- Uning
missingqatorlarini ma'noli test bilan yoping - Branch coverage bilan qayta o'lchang
Vazifa 4: 100% coverage tuzog'i
- Buzuq funksiya yozing (
assertsiz test 100% beradi) - Coverage 100% ekanini ko'rsating, lekin xato borligini isbotlang
assertqo'shib xatoni ushlang- Xulosa: coverage nima o'lchaydi va nima o'lchamaydi
Vazifa 5: fail_under bilan CI
pyproject.tomldafail_under = 80sozlang- Qamrov 80% dan past bo'lganda
coverage reportxato (chiqish kodi 2) berishini ko'rsating - Testlar qo'shib 80% dan oshiring
- Bu CI/CD (28-qism) da qanday ishlashini tushuntiring
Vazifa 6: Branch tuzog'i
Murakkab shartli funksiya (and, or, ichma-ich if):
- Statement coverage 100% beradigan minimal test yozing
- Branch coverage bilan qamralmagan tarmoqlanishlarni toping
- Ularni ham qamrang
- Statement va branch coverage farqini o'lchab ko'rsating
Vazifa 7: O'ylash
Coverage — kuchli, lekin xavfli metrika: menejerlar uni "sifat ko'rsatkichi" sifatida ishlatishga moyil ("90% coverage bo'lsin"), bu esa dasturchilarni ma'nosiz testlar yozishga undaydi (Goodhart qonuni: "metrika maqsadga aylansa, u yaxshi metrika bo'lishdan to'xtaydi"). Nima uchun coverage ni maqsad qilish teskari natija beradi, va coverage ni to'g'ri (foydali) ishlatishning yo'li qanday?
Javob
Qisqa javob: Coverage ni maqsad qilish Goodhart qonuniga tushadi: dasturchilar foizni oshirish uchun kodni ishga tushiradigan, lekin natijani tekshirmaydigan testlar yozadi. Foiz ko'tariladi, sifat esa yo'q. Coverage ni to'g'ri ishlatish — uni maqsad emas, vosita sifatida ko'rish: qaysi muhim kod test qilinmaganini topish uchun, keyin uni ma'noli test bilan yopish. Metrika o'zi yomon emas, uni maqsadga aylantirish yomon.
1. Nega coverage ni maqsad qilish yomon
| Muammo | Tafsilot |
|---|---|
| Goodhart qonuni | Metrika maqsad bo'lsa, buziladi |
| Ma'nosiz testlar | assert siz, faqat chaqiruv |
| Yolg'on xotirjamlik | "90% — xavfsiz" degan noto'g'ri ishonch |
| Vaqt isrofi | Arzimas kod uchun test yozish |
| Sifat emas, ko'rsatkich | Testlar sonini emas, sifatini quvish kerak |
2. Coverage nima o'lchaydi va nima o'lchamaydi
| O'lchaydi | O'lchamaydi |
|---|---|
| Qator bajarildimi | Natija to'g'rimi |
| Tarmoqlanish qamraldimi | Chegara holatlari ma'nolimi |
| Ko'r nuqtalar | Testlarning sifati |
| Qamrov foizi | Xatolar yo'qligi |
3. To'g'ri ishlatish
| Yondashuv | Foyda |
|---|---|
| Ko'r nuqtalarni topish | Yetishmayotgan muhim testlar |
| Xato yo'llarini ko'rsatish | except qamralmagani |
| Branch coverage | Shohobchalarni tekshirish |
CI da minimal (fail_under) |
Regressiyani oldini olish |
| Ma'noli test + coverage | Sifat va qamrov birga |
4. Goodhart qonuni umumiy
Bu faqat coverage emas — har qanday metrika maqsadga aylansa buziladi:
- Kod qatorlari soni → uzun, ortiqcha kod
- Bajarilgan vazifalar → mayda vazifalarga bo'lish
- Yopilgan xatolar → mayda xatolarni sun'iy yaratish
5. Amaliy qoida
- Coverage — diagnostika, maqsad emas
- Past coverage — "bu yerni tekshir" signali
- Yuqori coverage — kafolat emas, faqat ko'p qamrov
- Sifat: ma'noli assert + muhim yo'llar + xato holatlari
6. Xulosa
- Coverage ni maqsad qilish ma'nosiz testlarga olib keladi (Goodhart)
- Coverage qator bajarilganini o'lchaydi, to'g'riligini emas
- Uni ko'r nuqtalarni topish vositasi sifatida ishlating
- Ma'noli testlar + coverage = sifat
Nimani mustahkamlaydi: 2.1–2.8-bo'limlar.
Xulosa
Bu darsda coverage bilan testlar qamrovini o'lchashni o'rgandik.
Eng muhim uch fikr:
Coverage — ko'r nuqtalarni topish vositasi.
coverage run -m pytestvacoverage report -mtestlar kodning qaysi qatorlarini ishga tushirganini ko'rsatadi;missingustuni aynan qaysi qatorlar test qilinmaganini aytadi. Bu ko'r nuqtalar ko'pincha xato yo'llari (except,raise), chegara shartlari va kam ishlatiladigan funksiyalar — "baxtli yo'l" test qilinib, ular unutiladi.Branch coverage statement coverage dan ishonchliroq. Oddiy statement coverage
if x:bajarilganini belgilaydi, lekinxFalse bo'lgan holat qamralmagan bo'lishi mumkin;coverage run --branchhar shartning ikkala tomonini talab qiladi va qisman qamralgan (BrPart) tarmoqlanishlarni ko'rsatadi.pytest-covvapyproject.tomldagifail_underCI/CD da minimal qamrovni majburiy qiladi.100% coverage ≠ xatosiz kod. Coverage faqat qator bajarilganini o'lchaydi, to'g'ri ishlaganini emas:
assertsiz yokiassert x is not Nonekabi ma'nosiz test coverage ni oshiradi, lekin xatoni ushlamaydi. Coverage ni maqsad qilish Goodhart qonuniga tushadi — foiz uchun ma'nosiz test yoziladi. Uni sifat metrikasi emas, diagnostika sifatida ishlating: muhim yo'llarni ma'noli testlar bilan qamrang, foizni quvmang.
Keyingi darsda TDD (Test-Driven Development) ni o'rganamiz: testni koddan oldin yozish falsafasini — qizil (test yiqiladi) → yashil (kod yoziladi) → refaktoring siklini va u dizaynga qanday ta'sir qilishini.
Izohlar (0)
Izoh yozish uchun kiring.
- Hozircha izoh yo'q. Birinchi bo'ling!