Darslik · 2026-08-16 · ~6 daqiqa o‘qiladi · boshlang'ich
pytest-django: birinchi testni yozamiz
Mundarija
Kod yozdingiz, brauzerda ochib bosib ko'rdingiz — ishlayapti. Bir haftadan keyin boshqa joyini o'zgartirdingiz va bilmagan holda avvalgi ishlagan joyni buzdingiz. Buni foydalanuvchi topib beradi. Tanish holatmi? Men ham shu yo'ldan o'tganman va testlarga jiddiy qarashim aynan ToDo loyihasidan boshlangan — uni ataylab "test intizomini o'rganish" maqsadida qurganman.
Testning ma'nosini bitta gap bilan aytish mumkin: bosib ko'rishni kod qilib yozib qo'yish. Bir marta yozasiz, keyin har o'zgarishdan so'ng kompyuter siz uchun ming marta bosib ko'radi.
Nega aynan pytest#
Django'ning o'z test tizimi bor (unittest asosida), lekin Python olamida
amalda standart — pytest: assert'lari oddiy, chiqishi o'qishli, fixture
tizimi kuchli. Django bilan do'stlashtirish uchun bitta plagin yetadi:
uv add --dev pytest pytest-django
Sozlama ham bitta fayl — pytest'ga Django sozlamalarini qayerdan olishni aytamiz:
# pytest.ini (loyiha ildizida)
[pytest]
DJANGO_SETTINGS_MODULE = config.settings
python_files = test_*.py
Loyiha va birinchi test#
Misolimiz — ToDo ilovasining soddalashtirilgan modeli:
# apps/todos/models.py
from django.db import models
from django.utils import timezone
class Task(models.Model):
title = models.CharField(max_length=200)
is_done = models.BooleanField(default=False)
due_date = models.DateField(null=True, blank=True)
@property
def is_overdue(self) -> bool:
# muddat o'tgan va hali bajarilmagan — kechikkan
if self.due_date is None or self.is_done:
return False
return self.due_date < timezone.localdate()
is_overdue — test yozishni boshlash uchun ideal nomzod: kichkina, lekin
ichida uchta shart yashiringan mantiq. Test fayli model bilan yonma-yon
turadi:
apps/todos/
├── models.py
└── tests/
├── __init__.py
└── test_models.py ← birinchi testimiz shu yerda
# apps/todos/tests/test_models.py
from datetime import timedelta
import pytest
from django.utils import timezone
from apps.todos.models import Task
# kecha va ertaga — testlarda qayta-qayta kerak bo'ladi
KECHA = timezone.localdate() - timedelta(days=1)
ERTAGA = timezone.localdate() + timedelta(days=1)
@pytest.mark.django_db
def test_muddati_otgan_vazifa_kechikkan():
task = Task.objects.create(title="Hisobot", due_date=KECHA)
assert task.is_overdue
@pytest.mark.django_db
def test_bajarilgan_vazifa_kechikkan_hisoblanmaydi():
task = Task.objects.create(title="Hisobot", due_date=KECHA, is_done=True)
assert not task.is_overdue
@pytest.mark.django_db
def test_muddatsiz_vazifa_kechikmaydi():
task = Task.objects.create(title="Kitob o'qish")
assert not task.is_overdue
Ishga tushiramiz:
uv run pytest
# ...
# 3 passed in 0.42s
Uch nuqtaga e'tibor qarataman. Birinchisi — @pytest.mark.django_db
belgisi: usiz test bazaga tegolmaydi. Bu ataylab qilingan, chunki bazasiz
test yashin tezligida yuradi va pytest sizni "bazani faqat kerak joyda
ishlat" deb tarbiyalaydi. Ikkinchisi — test nomlari o'zbekcha va gap kabi
o'qiladi: test yiqilganda nomining o'zi nima buzilganini aytib turadi.
Uchinchisi — har test bitta narsani tekshiradi: uchta shartga uchta
alohida test, bitta katta test emas.
Test bazasi haqida xotirjam bo'ling#
Boshlovchilarni ko'p tashvishlantiradigan savol: "testlar mening bazamni
buzib qo'ymaydimi?" Yo'q. pytest-django har test seansi uchun alohida,
vaqtinchalik baza yaratadi (nomi odatda test_ bilan boshlanadi), ishini
o'sha yerda qiladi va oxirida o'chirib tashlaydi. Har test esa tranzaksiya
ichida yuradi va tugagach orqaga qaytariladi — ya'ni testlar bir-birining
ma'lumotini ham ko'rmaydi. Siz Task.objects.create bilan nima yaratmang,
haqiqiy bazangizga bitta yozuv ham tushmaydi.
Yiqilgan test — bu yaxshi test#
Endi eng muhim mashqni qilamiz: mantiqni ataylab buzamiz. is_overduedagi
self.is_done shartini olib tashlab, testlarni qayta ishga tushiring:
FAILED test_bajarilgan_vazifa_kechikkan_hisoblanmaydi
assert not task.is_overdue
E assert not True
Mana shu qizil satr — testlarning butun qiymati. Siz xatoni foydalanuvchidan emas, terminaldan, o'zgarish qilgan daqiqangizda eshitdingiz. Endi shartni joyiga qaytaring — yashil. Bu tsiklni his qilgan odam testsiz loyihaga qaytishi qiyin.
Testni qachon yozish kerak?
Ideal javob "koddan oldin" (TDD), lekin halol boshlanish — "kod bilan
birga": yangi mantiq yozdingizmi, o'sha o'tirishning o'zida 2-3 test
ham yozing. Eng foydali joylar — shartli mantiq (is_overdue kabi),
hisob-kitoblar va chegaraviy holatlar. Getter-setter'larga test yozib
vaqt ketkazmang.
Yakun#
pytest-django'ni ishga tushirish ikki qadam edi: plagin va pytest.ini.
Undan keyingisi — odat masalasi: har mantiqqa uch-to'rt satr test, nomlari
gap kabi, har biri bitta narsani tekshiradi. Baza haqida qayg'urmaysiz —
u vaqtinchalik va sizniki emas.
Keyingi qismda ko'lamni kengaytiramiz: unit va integration testlar farqi — "kichik va tez" bilan "katta va ishonchli" o'rtasidagi muvozanatni qanday tanlash.