Python’da Kodunuzu Kırılmaktan Koruyun: pytest ile Birim Testi Yazmak

Kodunuz çalışıyor, ama gerçekten çalıştığından nasıl emin olabilirsiniz? Elle her seferinde birkaç örnek deneyip “sanırım tamam” demek yerine, bu güveni otomatikleştirebilirsiniz. İşte tam bu ihtiyaç için var olan araç pytest: yazdığınız her fonksiyonun beklendiği gibi davrandığını, siz kod değiştirdikten sonra bile saniyeler içinde doğrulayan bir test çerçevesi (framework).

Bu Proje Ne Yapıyor?

Bu projede iki basit ama gerçekçi fonksiyon üzerinden birim testinin (unit test) temellerini kuruyoruz: divide_numbers, iki sayıyı bölüyor ve paydası sıfır olursa açıkça bir ValueError fırlatıyor; calculate_average ise bir sayı listesinin ortalamasını hesaplıyor ve liste boşsa çökmek yerine güvenle 0.0 döndürüyor.

Asıl mesele bu iki fonksiyonun kendisi değil — mesele, bunların doğru çalıştığını nasıl kanıtladığımız. test_math_operations.py dosyasında, her biri belirli bir senaryoyu doğrulayan beş ayrı test fonksiyonu yazıyoruz: normal bölme, sıfıra bölme hatası, standart ortalama, boş liste ve tek elemanlı liste. pytest bu dosyayı otomatik olarak bulup çalıştırıyor ve her senaryonun sonucunu tek tek raporluyor.

Bu yaklaşımın gücü şurada: yarın calculate_average fonksiyonunu değiştirirseniz (ör. performansı artırmak için), bu beş test aynı davranışın korunduğunu birkaç saniyede doğrular. Elle test etmeyi unutursanız fark etmezsiniz; pytest hiçbir zaman unutmaz.

Kodun Anatomisi

pytest‘in en güçlü yanı, test yazmanın son derece sade olması: özel bir sınıfa ya da karmaşık bir kuruluma gerek yok, sadece adı test_ ile başlayan bir fonksiyon ve içinde birkaç assert (onayla) ifadesi yeterli.

Ortam Bilgisi
Yazar: Ahmet Aksoy · Tarih: 23.05.2026 · Python 3.12 · Ubuntu 24.04

# math_operations.py — test edilecek iş mantığı
def divide_numbers(numerator: float, denominator: float) -> float:
    if denominator == 0:
        raise ValueError("Denominator cannot be zero.")
    return numerator / denominator


# test_math_operations.py — doğrulayan testler
import pytest
from math_operations import divide_numbers, calculate_average

def test_divide_numbers_success():
    assert divide_numbers(10, 2) == 5.0
    assert divide_numbers(5, 2) == 2.5

def test_divide_numbers_by_zero():
    with pytest.raises(ValueError) as exc_info:
        divide_numbers(10, 0)
    assert str(exc_info.value) == "Denominator cannot be zero."

def test_calculate_average_empty_list():
    assert calculate_average([]) == 0.0

İki detaya dikkat edin. Birincisi, test_divide_numbers_success içindeki her assert satırı, ifadenin doğru olmasını “onaylıyor” — yanlışsa test otomatik olarak başarısız (fail) sayılıyor. İkincisi, with pytest.raises(ValueError) bloğu özel bir istisna (exception) testi: burada beklenen davranış fonksiyonun normal bir değer değil, doğru hatayı fırlatması. Bu, hata yönetiminizin de test kapsamında olduğu anlamına geliyor — çoğu yeni başlayan geliştiricinin atladığı bir nokta.

Son olarak pytest, adı test_ ile başlayan her dosyayı ve içindeki test_ ile başlayan her fonksiyonu otomatik keşfeder (test discovery) — hiçbir yere kayıt etmenize gerek yok.

Nasıl Çalıştırılır?

pytest standart kütüphanenin parçası değil, önce sanal ortamınıza kurmanız gerekiyor:

pip install pytest

Ardından proje klasöründe çalıştırın:

pytest -v

-v (verbose) bayrağı, her test senaryosunu tek tek isimleriyle listeleyip sonucunu gösterir:

test_math_operations.py::test_divide_numbers_success PASSED
test_math_operations.py::test_divide_numbers_by_zero PASSED
test_math_operations.py::test_calculate_average_normal_list PASSED
test_math_operations.py::test_calculate_average_empty_list PASSED
test_math_operations.py::test_calculate_average_single_element PASSED

===================== 5 passed in 0.02s =====================

Beş yeşil PASSED satırı görünce, kodunuzun beklediğiniz gibi davrandığından emin olabilirsiniz — elle tek tek denemenize gerek kalmadan.

Ne Öğrendik?

  • pytest‘in isim tabanlı otomatik test keşfinin (test_ öneki) nasıl çalıştığı — hiçbir manuel kayıt gerekmiyor.
  • Basit assert ifadeleriyle beklenen değerlerin nasıl doğrulandığı.
  • pytest.raises() context manager’ıyla bir fonksiyonun doğru istisnayı doğru mesajla fırlattığının nasıl test edildiği.
  • Uç durumların (edge case) — burada boş liste ve tek elemanlı liste — neden ayrı test senaryoları hak ettiği.
  • Testlerin, kodu değiştirdiğinizde hiçbir şeyi bozmadığınızı saniyeler içinde doğrulayan bir güvenlik ağı olduğu.

Kaynaklar ve Sonraki Adımlar

Bu temel yapıyı ileri götürmek isterseniz: tekrarlayan girdi/çıktı çiftlerini tek bir testte toplamak için @pytest.mark.parametrize dekoratörüne bakabilir, testler arasında ortak hazırlık kodu paylaşmak için fixture (hazırlık yapısı) mekanizmasını keşfedebilir, ya da kod tabanınızın ne kadarının test edildiğini ölçmek için pytest-cov eklentisini deneyebilirsiniz. Her biri, güvenilir yazılım yazma yolunda bir sonraki doğal adım.

Ahmet Aksoy

Not: Bu yazıda incelediğimiz kodu ve benzer projelerin kaynak kodlarını github.com/ahmetax/practical-python-examples adresinde bulabilirsiniz.

Bir Yanıt Bırak

E-posta adresiniz yayınlanmayacak. Gerekli alanlar * ile işaretlenmişlerdir