Merhaba! Önceki dersimizde, PySpark ETL dönüşümlerimizi çeşitli veri senaryolarına karşı sağlamlaştırmak için pytest.mark.parametrize kullanarak testlerimizi nasıl daha güçlü ve sürdürülebilir hale getireceğimizi öğrendik. Artık tek bir test fonksiyonuyla hem "mutlu yolu" hem de null değerler gibi sınır durumlarını kapsayabiliyoruz.
Bu, test yazma becerimizde önemli bir adımdı. Ancak, bu testleri geliştirme ortamınızdan (örneğin VS Code veya PyCharm) çalıştırmakla, onları tam otomatik bir CI/CD (Sürekli Entegrasyon/Sürekli Dağıtım) işlem hattında çalıştırmak arasında önemli bir fark vardır. CI sunucuları bir grafik arayüze sahip değildir; her şeyi komut satırından (command line) yönetirler.
Bu derste, CI/CD'ye giden yolda kritik bir adım atacağız: pytest'i komut satırından nasıl çalıştıracağımızı ve test sonuçlarını, özellikle de başarısızlık raporlarını nasıl yorumlayacağımızı öğreneceğiz. Bu beceri, testlerinizi otomatize etme ve veri işlem hatlarınızın güvenilirliğini sağlama hedefinizin temelini oluşturur.
Neden Komut Satırı?
CI/CD sistemleri (GitHub Actions, Jenkins, vb.) temel olarak, belirttiğiniz komutları uzak bir makinede yürüten otomasyon sunucularıdır. Testlerinizi çalıştırmak için, CI sunucusuna tam olarak hangi komutu yürüteceğini söylemeniz gerekir.
Bu konunun CI/CD entegrasyonu için neden bu kadar önemli olduğunu anlamak için kısa bir video izleyelim.
PyTest Tutorial #3 - Execute PyTest Tests from Command Line
Software Testing Mentor kanalından bu video, testlerin neden komut satırından çalıştırılması gerektiğini ve bunun Jenkins gibi CI araçlarıyla nasıl bir ilişkisi olduğunu basitçe açıklıyor.
Videonun 00:45 - 01:27 arasındaki bölümünü izleyin. Sunucunun, komut satırı ile test çalıştırmanın CI entegrasyonları için neden zorunlu olduğundan bahsettiği kısma odaklanın.
Temel Test Çalıştırma
Projenizin kök dizinindeyken bir terminal açın. pytest'i çalıştırmak şaşırtıcı derecede basittir.
pytest komutunu çalıştırdığınızda, pytest otomatik olarak mevcut dizinde ve alt dizinlerde testleri arar. Standart olarak, test_*.py veya *_test.py adlandırma kuralına uyan dosyaları ve bu dosyalardaki test_ ile başlayan fonksiyonları "keşfeder" ve çalıştırır.
Terminalinize gidin ve projenizin kök dizininde aşağıdaki komutu çalıştırın:
pytest
Çıktı, çalıştırılan test sayısını ve her birinin sonucunu gösteren kompakt bir özet olacaktır. Önceki derste parametrize ile yazdığınız testler sayesinde, birden fazla testin çalıştığını görmelisiniz. Çıktı şuna benzer olacaktır:
============================= test session starts ==============================
...
collected 4 items
tests/test_transformations.py .... [100%]
============================== 4 passed in Xs ===============================
Buradaki her bir . (nokta), başarıyla geçen bir testi temsil eder.
Test Çıktısını Detaylandırma: -v ve -s
Varsayılan çıktı çok minimalisttir. Hangi testlerin çalıştığını ve daha fazla detayı görmek için bazı komut satırı bayrakları (flags) kullanabiliriz.
-vveya--verbose: Bu bayrak, "ayrıntılı" (verbose) modunu etkinleştirir. Her testin adını ve sonucunu ayrı ayrı listeler. Önceki derstepytest.paramile eklediğimizid'lerin ne kadar faydalı olduğunu burada göreceksiniz.-s:pytestnormalde testler çalışırkenprint()ifadelerinin çıktılarını "yakalar" ve sadece test başarısız olursa gösterir.-sbayrağı bu yakalamayı devre dışı bırakır veprintçıktılarının anında terminalde görünmesini sağlar. Bu, hata ayıklama (debugging) için çok yararlıdır.
Bu komutları nasıl kullanacağımızı görelim.
PyTest Tutorial #3 - Execute PyTest Tests from Command Line
Şimdi, Software Testing Mentor kanalının aynı videosundan -v ve -s bayraklarının kullanımını gösteren bölümleri izleyelim.
Önce 06:17 - 07:33 arasını izleyerek -v bayrağının çıktıyı nasıl daha okunabilir hale getirdiğini görün. Ardından 08:25 - 08:49 arasını izleyerek -s bayrağının test içindeki print ifadelerini nasıl görünür kıldığını öğrenin. İkisini bir arada (pytest -vs) da kullanabileceğinize dikkat edin.
Şimdi terminalde pytest -v komutunu çalıştırın. Çıktının nasıl değiştiğini gözlemleyin. test_with_full_name[happy_path] gibi açıklayıcı isimler görmelisiniz.
Başarısızlık Raporlarını Yorumlama
Testlerin asıl değeri, bir şeyler ters gittiğinde ortaya çıkar. pytest, başarısız testler hakkında son derece ayrıntılı ve faydalı raporlar sunar.
Bunu görmek için, testlerimizden birini kasıtlı olarak bozalım. tests/test_transformations.py dosyasını açın ve happy_path senaryosundaki expected_data'yı değiştirin:
# ...
pytest.param(
[{"first_name": "John", "last_name": "Doe"}],
# Beklenen çıktıyı kasıtlı olarak yanlış yapalım
[{"first_name": "John", "last_name": "Doe", "full_name": "John-Doe"}],
id="happy_path"
),
# ...
Şimdi terminalde pytest -v komutunu tekrar çalıştırın. Çıktı bu sefer çok farklı olacak.
Aşağıdaki referans metnini okuyarak pytest'in başarısızlık raporlarını nasıl yapılandırdığını inceleyelim.
Effective Python Testing With pytest
Real Python'daki bu makale, pytest çıktısının nasıl yorumlanacağını mükemmel bir şekilde açıklıyor.
Makaledeki 'Nicer Output' başlığı altındaki bölümü okuyun. Yazarın, pytest çıktısını nasıl bölümlere ayırdığını inceleyin: sistem bilgileri, test ilerlemesi (. , F, E karakterleri) ve en önemlisi, FAILURES bölümündeki detaylı hata raporu.
Okuduğunuz gibi, pytest raporu birkaç ana bölümden oluşur:
- İlerleme Satırı:
happy_pathtestinizin yanında artık bir.yerineF(Failed) harfi göreceksiniz. FAILURESBölümü: Raporun en önemli kısmıdır.- Hangi testin (
test_with_full_name[happy_path]) başarısız olduğunu belirtir. - Hatanın kaynağı olan satırı (
assertDataFrameEqual(...)) gösterir. pyspark.testing.utilstarafından sağlanan, beklenen DataFrame ile gerçekte üretilen DataFrame arasındaki farkı gösteren ayrıntılı bir "diff" sunar. Bu, hatanın nedenini anlamak için paha biçilmezdir.
- Hangi testin (
Aşağıdaki görsel, basit bir assert ifadesi için pytest'in ürettiği ayrıntılı fark raporuna güzel bir örnektir. PySpark testimizdeki çıktı farklı görünse de, temel fikir aynıdır: pytest size neyin yanlış gittiğini tam olarak göstermeye çalışır.

İşi bitirdikten sonra, testinizi tekrar eski, doğru haline getirmeyi unutmayın.
CI/CD için Gelişmiş Komutlar
Testlerimizi otomatikleştirmeye yaklaştıkça, pytest'i daha hassas bir şekilde kontrol etmemizi sağlayan birkaç komutu daha öğrenmemiz faydalı olacaktır.
Belirli Testleri Çalıştırma
Tüm test suitini çalıştırmak zaman alabilir. Bazen sadece belirli bir dosyadaki veya belirli bir anahtar kelimeyle eşleşen testleri çalıştırmak isteyebilirsiniz.
- Belirli bir dosyayı çalıştırma:
pytest tests/test_transformations.py - Anahtar kelime (
-k) ile çalıştırma:-kbayrağı, adında belirtilen ifadeyi içeren testleri çalıştırır. Bu, özellikle tek birparametrizesenaryosunu yeniden çalıştırmak için kullanışlıdır.pytest -k "null_last_name"
Aşağıdaki video bu özelliğin nasıl kullanıldığını göstermektedir.
PyTest Tutorial #3 - Execute PyTest Tests from Command Line
Software Testing Mentor'un videosundan, -k bayrağını kullanarak belirli testleri bir anahtar kelime ifadesiyle nasıl hedefleyeceğimizi öğrenelim.
Videonun 09:06 - 10:34 arasındaki bölümünü izleyin. Sunucunun, bir dosya belirttikten sonra -k ve bir anahtar kelime (log) kullanarak yalnızca eşleşen testleri nasıl çalıştırdığına dikkat edin.
Çıkış Kodları (Exit Codes)
Bu, CI/CD için en kritik konulardan biridir. Bir komut tamamlandığında, işletim sistemine bir "çıkış kodu" (exit code) döndürür. Bu, komutun başarılı olup olmadığını bildiren bir sayıdır. Kural olarak:
- Çıkış kodu
0başarı anlamına gelir. - Sıfırdan farklı bir çıkış kodu hata anlamına gelir.
CI işlem hattınız, test komutunun çıkış kodunu kontrol eder. Kod 0 ise bir sonraki adıma (örneğin, Docker imajı oluşturma) geçer. Eğer 0 değilse, işlem hattını durdurur ve başarısız olarak işaretler.
pytest'in ana çıkış kodlarını öğrenmek için resmi dokümantasyonuna başvuralım.
Usage and Invocations - pytest documentation
pytest'in resmi dokümantasyonu, olası çıkış kodlarını net bir şekilde listeler. Bu, CI yapılandırmalarında ne bekleyeceğinizi anlamak için temel bir bilgidir.
Dokümantasyonda 'Possible exit codes' başlığı altındaki bölümü okuyun. En azından şu kodların anlamını not edin: Exit code 0 (tüm testler geçti), Exit code 1 (bazı testler başarısız oldu) ve Exit code 5 (hiç test bulunamadı).
Diğer Faydalı Bayraklar
--durations=N: En yavaşNtesti raporlar. Test süitiniz yavaşlamaya başladığında performans darboğazlarını bulmak için harikadır.-r<karakterler>: Test oturumunun sonunda kısa bir özet raporu gösterir. Örneğin,pytest -ra, geçenler (pveP) dışındaki tüm sonuç kategorileri (failed, error, skipped, xfailed, xpassed) için ayrıntılı bir özet sunar.--help:pytest'in tüm komut satırı seçeneklerini görmek içinpytest --helpkomutunu kullanabilirsiniz.
Özet ve Sonraki Adımlar
Bu dersle, testlerinizi bir otomasyon ortamında çalıştırmanın temellerini attınız. Artık sadece test yazmakla kalmıyor, aynı zamanda onları bir CI sunucusunun göreceği şekilde çalıştırıp sonuçlarını yorumlayabiliyorsunuz.
Temel Çıkarımlar:
- CI/CD işlem hatları, testleri
pytestgibi komutlarla komut satırından çalıştırır. -v(verbose),-s(no-capture) ve-k(keyword) gibi bayraklar, testlerin çalıştırılmasını ve çıktısını kontrol etmenizi sağlar.pytest'in başarısızlık raporları, hatanın yerini ve nedenini anlamak için zengin bilgiler (traceback, diffs) sunar.pytest'in çıkış kodları (0başarı,>0hata), CI işlem hattının akışını kontrol eder.
Gelecek Dersin Önizlemesi:
Artık kodumuzun davranışını test etmek için sağlam bir temele sahibiz. Bir sonraki adımda, kodumuzun kendisini, yani stilini ve kalitesini güvence altına alacağız. Modül 2'ye geçerek, kodumuzdaki potansiyel hataları ve stil sorunlarını otomatik olarak bulan ruff ile linting ve formatlama konusunu işleyeceğiz. Bu kontrolleri, her git commit işleminden önce otomatik olarak çalışacak şekilde pre-commit kancalarıyla nasıl entegre edeceğimizi öğreneceğiz. Bu, tutarlı ve yüksek kaliteli bir kod tabanı sürdürmenin ilk adımıdır.