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 verirKodu 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}")