Skip to main content

Welcome to a Grasp lesson

Create a free account to keep studying and create your own study path.

Lesson 7

Running Pytest and Interpreting Results

Recommended resources

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.

  • -v veya --verbose: Bu bayrak, "ayrıntılı" (verbose) modunu etkinleştirir. Her testin adını ve sonucunu ayrı ayrı listeler. Önceki derste pytest.param ile eklediğimiz id'lerin ne kadar faydalı olduğunu burada göreceksiniz.
  • -s: pytest normalde testler çalışırken print() ifadelerinin çıktılarını "yakalar" ve sadece test başarısız olursa gösterir. -s bayrağı bu yakalamayı devre dışı bırakır ve print çı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:

  1. İlerleme Satırı: happy_path testinizin yanında artık bir . yerine F (Failed) harfi göreceksiniz.
  2. FAILURES Bö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.utils tarafı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.

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.

Pytest Verbose Output with Failure Report
Görsel: `pytest -v` komutunun çıktısı. Başarılı olan testler (PASSED) ve başarısız olan bir test (FAILED) gösteriliyor. Başarısızlık raporu, hatanın olduğu satırı ve beklenen ile gerçek değer arasındaki farkı ("Full diff") ayrıntılı olarak sunuyor.

İş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: -k bayrağı, adında belirtilen ifadeyi içeren testleri çalıştırır. Bu, özellikle tek bir parametrize senaryosunu 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 0 baş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ş N testi 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 (p ve P) 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çin pytest --help komutunu 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 pytest gibi 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ı (0 başarı, >0 hata), 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.