10 - Birim Test, Test Güdümlü Geliştirme (TDD) ve Debugging
2025
unittest
Modülüunittest.TestCase
’den miras alan bir test sınıfı yaz.test_
ile başlayan test metotları tanımla.unittest
ile Basit Toplama TestiKodumuz (matematik.py
):
Testimiz (test_matematik.py
):
import unittest
from matematik import topla
class TestToplama(unittest.TestCase):
def test_iki_pozitif(self):
sonuc = topla(5, 3)
# Vurgu: Beklentimizi kontrol ediyoruz
self.assertEqual(sonuc, 8)
def test_pozitif_negatif(self):
sonuc = topla(10, -2)
self.assertEqual(sonuc, 8)
Terminalden çalıştırma: python -m unittest test_matematik.py
unittest.TestCase
sınıfında birçok assertion metodu bulunur:
assertEqual(a, b)
: a
ile b
eşit mi?assertNotEqual(a, b)
: a
ile b
farklı mı?assertTrue(x)
: x
doğru (True) mu?assertFalse(x)
: x
yanlış (False) mu?assertIsNone(x)
: x
None mı?assertIsNotNone(x)
: x
None değil mi?assertRaises(HataTipi, fonksiyon, argümanlar...)
: Fonksiyon çağrıldığında belirtilen hatayı fırlatıyor mu?pytest
Kütüphanesipip install pytest
)assert
ifadesini kullanır.pytest
ile Yazmak# test_matematik_pytest.py
from matematik import topla
def test_iki_pozitif():
sonuc = topla(5, 3)
# Vurgu: Standart assert kullanımı
assert sonuc == 8 #[5]
def test_pozitif_negatif():
sonuc = topla(10, -2)
assert sonuc == 8 #[9]
# Terminalden çalıştırma: pytest
Çoğu zaman pytest
daha okunaklı ve hızlıdır.
Diyelim ki bir string’deki boşlukları sayan bosluk_say(metin)
fonksiyonunuz var. Bu fonksiyon için aklınıza gelen 2 farklı test durumu ne olurdu? (Ne tür metinler gönderirdiniz?)
(Cevaplar: Boş metin ““, hiç boşluk olmayan”abc”, başta/sonda boşluk ” test “, normal”bu bir test” vb.)
requests.get(...)
)API’den veri çeken fonksiyon:
Test (Gerçek API’ye bağlanmadan):
# test_app.py
import unittest
from unittest.mock import patch, Mock # Mock ve patch lazım
from app_code import get_kullanici_adi
class TestAPI(unittest.TestCase):
@patch('app_code.requests.get') # requests.get'i taklit et
def test_kullanici_adi_getir(self, mock_get): # mock_get taklit nesnesi
# Taklit nesne nasıl davransın?
mock_response = Mock()
mock_response.json.return_value = {"name": "Ayşe"} # .json() -> {"name": "Ayşe"}
mock_get.return_value = mock_response # get() -> mock_response
isim = get_kullanici_adi(5) # Fonksiyonu çağır (mock çalışacak)
mock_get.assert_called_once_with("https://api.example.com/users/5") # Doğru URL çağrıldı mı?
self.assertEqual(isim, "Ayşe") # Doğru isim geldi mi?
@patch
, requests.get
yerine mock_get
nesnesini kullanmamızı sağladı.
Bir dosyaya log kaydı yazan bir fonksiyonu test etmek istiyorsunuz. Testlerinizin gerçek bir dosya oluşturmasını istemiyorsunuz. Bu durumda neyi “mock” ederdiniz (taklit ederdiniz)?
(Cevap: Dosya açma (open
) işlemini veya dosyaya yazma (write
) metodunu)
RED
-> Önce Başarısız bir test yaz (kod yok).GREEN
-> Testi Başarılı yapacak en basit kodu yaz.REFACTOR
-> Kodu İyileştir (testler hala başarılı).+--------------------------+ +--------------------------+ +-----------------------+
| 1. Test Yaz (RED) | ---> | 2. Kodu Yaz (GREEN) | ---> | 3. Kodu İyileştir |
| (Başarısız olacak | | (Testi geçecek en | | (REFACTOR) |
| çünkü kod yok) | | basit kod) | | (Testler hala yeşil) |
+--------------------------+ +--------------------------+ +-----------------------+
^ |
|--------------------<---- Yeni Test Ekle <-------------------------+
İstek: is_pozitif(sayi)
fonksiyonu yaz.
RED: Testi yaz (test_pozitif.py
):
GREEN: En basit kodu yaz (sayi_kontrol.py
):
Testi tekrar yaz/çalıştır (test_pozitif.py
):
REFACTOR: Yeni test (negatif için) ekle (RED):
# test_pozitif.py
# ... önceki test ...
def test_negatif_icin_false(): assert is_pozitif(-3) == False # Hata verir
Kodu düzelt (GREEN & REFACTOR):
Tüm testler şimdi geçer.
print()
ile Debugging:
print(degisken)
ekleyerek değerleri takip etmek.pdb
):
import pdb; pdb.set_trace()
eklenir.[ Kod Çalışır ] ---> [ Beklenmedik Sonuç / Hata ]
|
V
[ Şüpheli Bölgeye Breakpoint Koy ]
|
V
[ Programı Debug Modunda Çalıştır ] ---> [ Kod Breakpoint'te Durur ]
| |
V V
[ Değişkenleri İncele ('Inspect') ] <--- [ Adım Adım İlerle ('Step') ] ---> [ Hatanın Kaynağını Bul ]
Çok karmaşık bir matematiksel hesaplama yapan ve ara sıra yanlış sonuç veren bir fonksiyonunuz var. Hatayı bulmak için hangi debugging yöntemini öncelikle tercih ederdiniz? Neden?
print()
eklemekpdb
kullanmak(Cevap: Genellikle (B) en etkilidir, çünkü değişkenleri adım adım takip etmek ve kod akışını görmek karmaşık durumlarda daha kolaydır. print
yetersiz kalabilir, pdb
ise IDE kadar görsel olmayabilir.)
unittest
, pytest
)unittest.mock
)print
, IDE Debugger, pdb
).Test yazmak ve hata ayıklamak, profesyonel yazılım geliştirmenin temel adımlarıdır!
assert a == b
).unittest
’te bir grup testi içeren sınıf.unittest
modülü, pytest
komutu).pytest
veya unittest
):
metin_islemleri.py
dosyasına, bir string’i ters çeviren ters_cevir(metin)
fonksiyonu yazın.test_metin.py
dosyası oluşturun:
"python"
-> "nohtyp"
)""
-> ""
)"madam"
-> "madam"
)print
veya Debugger):
liste = [-1, -5, -2, -8, -3]
ve liste = []
durumlarında hatanın nerede olduğunu ve nedenini bulun.# hatali_kod.py
def en_buyuk_sayi(liste):
en_buyuk = None # Başlangıç değeri sorunlu olabilir
for sayi in liste:
# None ile karşılaştırma veya ilk elemanı atama mantığı eksik
if en_buyuk is None or sayi > en_buyuk:
en_buyuk = sayi
return en_buyuk
# Test Durumları
# sonuc1 = en_buyuk_sayi([1, 5, 2, 8, 3]) # Bu doğru çalışır (8)
sonuc2 = en_buyuk_sayi([-1, -5, -2, -8, -3]) # Ne döndürmeli? Ne döndürüyor?
sonuc3 = en_buyuk_sayi([]) # Ne döndürmeli? Ne döndürüyor?
print(f"Negatif Liste Sonuç: {sonuc2}")
print(f"Boş Liste Sonuç: {sonuc3}")