Ünite 10 / 11

Sahte-Güven Riski, Test Kalitesi ve Mutasyon Testi: Testleri Test Etmek

Kazanimlar:

  • Sahte-güvenin üç yüzünü (assert'siz, kendini doğrulayan, önemsiz assert) tanıyıp panzehirlerini uygulayabilme
  • Mutasyon testini ve mutasyon skorunu kapsam yüzdesinden daha dürüst bir kalite ölçüsü olarak araçla veya elle kullanabilme
  • Yapay zekayı testlere karşı bir kırmızı takım olarak konumlandırıp övgü tuzağına düşmeden test boşluklarını avlayabilme

Bu modülün merkezinde tekrar eden bir uyarı var: yeşil yanan bir test paneli, kalitenin kanıtı değildir. Testleriniz size güven veriyorsa, o güvenin gerçek mi yoksa sahte mi olduğunu bilmeniz gerekir. Yapay zeka (YZ) çağında bu soru her zamankinden kritik, çünkü YZ akıcı, düzgün görünen ama içi boş testler üretmekte ustadır. Sahte-güven (false confidence — testler yeşil olduğu için yazılımın doğru olduğuna inanmak, oysa testler aslında hiçbir şeyi doğrulamıyor), bir QA ekibinin başına gelebilecek en tehlikeli durumdur; çünkü hata olmadığını değil, hataları göremediğinizi gizler. Bu ünite, tüm modülün doğrulama felsefesini tek bir disiplinde toplar: testlerinizi test etmek.

Testin kalitesini ölçmenin altın standardı: mutasyon testi

Bir testin gerçekten koruyup korumadığını anlamanın en güçlü yolu mutasyon testidir (mutation testing — kaynak kodda kasıtlı küçük bozmalar/mutasyonlar üretip, testlerin bu bozmaları yakalayıp yakalamadığını ölçen teknik). Mantık basittir: kodu kasten bozarsanız (bir +'yı - yapmak, bir >'yı >= yapmak, bir true'yu false yapmak), iyi bir test paketi bu bozmayı yakalayıp kırmızıya dönmelidir. Dönmüyorsa, o bozma hayatta kalmıştır (survived mutant) — yani testleriniz o davranışı aslında korumuyor.

Mutasyon skoru = öldürülen mutasyon / toplam mutasyon. %90 satır kapsamı olan bir paket, %40 mutasyon skoruna sahip olabilir; bu, satırların çalıştığını ama davranışın doğrulanmadığını gösterir. Mutasyon skoru, kapsam yüzdesinden çok daha dürüst bir kalite ölçüsüdür.

İpucu: Otomatik mutasyon araçları vardır (Java için PIT/Pitest, JavaScript/TypeScript için Stryker, .NET için Stryker.NET, Python için mutmut). Bunlar yüzlerce mutasyonu otomatik üretip test eder. Aracınız yoksa, elle "kodu bozarak sına" yöntemi bile kritik fonksiyonlar için çok değerlidir.

Sahte-güvenin üç yüzü ve panzehiri

Sahte-güven biçimi

Belirti

Panzehir

Assert'siz test

Kod çalışır, hiçbir şey doğrulanmaz

Her testte gerçek assert; mutasyonla sına

Kendini doğrulayan test

Beklenen = kodun çıktısı

Beklenen değeri bağımsız hesapla

Önemsiz assert

"null değil", "200 döndü"

İş kuralını/gerçek sonucu doğrula

Yüksek kapsam yanılgısı

%90 satır, düşük koruma

Mutasyon skoruna bak

Kırılgan test toleransı

"Yine takıldı, geç"

Kök neden + deterministik test

YZ'yi bir "kırmızı takım" olarak kullanmak

YZ hem sahte-güven üretebilir hem de onu avlamada güçlü bir müttefik olabilir. YZ'yi kendi testlerinize karşı bir kırmızı takım (red team — savunmayı sınamak için saldırgan gibi düşünen ekip) olarak kullanın: "bu testleri geçen ama yanlış olan bir kod yaz" veya "bu testleri kandıracak bir bozma bul" diye sorun. YZ testlerinizdeki boşlukları bulursa, o boşluklar gerçek risklerdir.

Dikkat: YZ'ye "test kalitem iyi mi" diye sorup "evet, harika" cevabını güvence sanmayın. YZ nazik olmaya meyleder. Bunun yerine YZ'yi somut bir göreve koşun: "bu testleri geçen bir hata üret." Üretebiliyorsa, testleriniz o hataya karşı kördür.

Eşdeğer mutasyonlar ve skorun sınırları

Mutasyon testi güçlüdür ama bir inceliği vardır: bazı mutasyonlar kodun davranışını hiç değiştirmez. Bunlara eşdeğer mutasyon (equivalent mutant — bozulmuş kod, orijinaliyle tamamen aynı sonucu üreten mutasyon) denir. Örneğin hiç kullanılmayan bir değişkenin başlangıç değerini değiştirmek çıktıyı etkilemez; hiçbir test bunu yakalayamaz ve yakalamamalıdır da. Bu yüzden %100 mutasyon skoru pratikte çoğu zaman ulaşılamaz ve hedef de değildir. Eşdeğer mutasyonları elle ayıklamak emek ister; bu yüzden mutasyon skorunu mutlak bir sınav notu gibi değil, "testlerim gerçekten koruyor mu" sorusuna dürüst bir gösterge olarak okuyun.

Pratik yaklaşım şudur: mutasyon testini tüm kod tabanında sürekli çalıştırmak yerine, en yüksek riskli ve en karmaşık iş kurallarını içeren modüllerde uygulayın. Bu modüllerde hayatta kalan mutasyonları tek tek inceleyin; gerçek bir boşluksa test ekleyin, eşdeğer mutasyonsa gerekçesiyle işaretleyip geçin. YZ, hayatta kalan bir mutasyonun eşdeğer olup olmadığını değerlendirmede ilk elemeyi yapabilir; ama nihai kararı, kodun ne yaptığını bilen siz verirsiniz.

Dikkat: Mutasyon testi hesaplama açısından pahalıdır (her mutasyon için tüm ilgili testler yeniden koşar). Bu yüzden onu her birleştirmede değil, kritik modüller için haftalık veya sürüm öncesi bir derin denetim olarak planlamak yaygın ve makul bir stratejidir.

Zayıf prompt / Güçlü prompt

Zayıf: "Testlerim yeterli mi?"
Güçlü: "Bu fonksiyon ve test paketi için bir kırmızı takım gibi davran. (1) Kodda öldürülebilecek 8 mutasyon üret (operatör değişimi, sınır kayması, koşul tersleme, dönüş değeri değişimi). (2) Her mutasyon için mevcut testlerden hangisinin onu yakalayacağını, hangisinin YAKALAMAYACAĞINI belirt. (3) Hayatta kalan her mutasyon için, onu öldürecek yeni bir test yaz. (4) Ayrıca bu testlerin tümünü geçen ama iş kuralını ihlal eden bir kod örneği üretebiliyorsan göster. Kod+testler: [yapıştır]"

Güçlü prompt; YZ'yi övgü makinesi değil, testleri kıran bir denetçi olarak konumlandırır.

Dört kopyalanabilir şablon

1) Elle mutasyon denetimi:

Bu kod için 8 anlamlı mutasyon (küçük kasıtlı bozma) üret:aritmetik operatör değişimi, karşılaştırma sınırı (> vs >=),mantıksal tersleme, dönüş/sabit değişimi, koşul atlama.Her mutasyon için mevcut testlerden hangisinin onu yakalayıpyakalamayacağını tahmin et. Kod+testler: [yapıştır]

2) Hayatta kalan mutasyonu öldürme:

Şu mutasyon test raporunda hayatta kalan (yakalanmayan)mutasyonlar var: [liste/rapor]. Her biri için, o mutasyonuöldürecek (kod o şekilde bozulunca kırmızıya dönecek) minimalbir test yaz. Testin hangi davranışı doğruladığını yorumla.

3) Kırmızı takım — testi kandır:

Aşağıdaki testleri TAMAMI GEÇECEK şekilde, ama şu iş kuralınıihlal eden bir kod uygulaması yazabilir misin: [iş kuralı].Yazabiliyorsan, bu testlerin hangi boşluğu buna izin veriyor?O boşluğu kapatacak testi de ekle. Testler: [yapıştır]

4) Test kalite denetimi:

Bu test paketini kalite açısından denetle. Her test için işaretle:- Gerçek assert var mı, yoksa dekor mu?- Beklenen değer bağımsız mı, koddan mı türetilmiş?- İş kuralını mı yoksa önemsiz bir şeyi mi doğruluyor?Sonunda tahmini bir "gerçek koruma skoru" ve en zayıf 3 testi ver.Testler: [yapıştır]

Üç mini vaka

Vaka 1 — Kapsam %92, mutasyon skoru %38. Bir ekip yüksek kapsamına güveniyordu. Stryker ile mutasyon testi çalıştırıldığında skorun %38 olduğu görüldü: üretilen mutasyonların çoğu hayatta kaldı. Bu, testlerin satırları çalıştırıp davranışı doğrulamadığının kanıtıydı. Ekip üç hafta test kalitesine yatırım yaptı; mutasyon skoru %81'e çıktı ve bir sonraki sürümde iki gerçek hesaplama hatası bu güçlenmiş testlerce yakalandı.

Vaka 2 — YZ testi kandırdı. Bir uzman, "kırmızı takım" şablonuyla YZ'den mevcut testleri geçen ama indirim kuralını ihlal eden bir kod istedi. YZ, indirimi hep sıfır döndüren bir kod yazdı — ve tüm testler yeşil kaldı, çünkü hiçbir test gerçek indirim değerini doğrulamıyordu. Boşluk görüldü, gerçek assert'ler eklendi.

Vaka 3 — Övgü tuzağı. Bir junior testçi YZ'ye "testlerim iyi mi" diye sordu, "çok kapsamlı" cevabını alıp rahatladı. Kıdemli meslektaşı "test kalite denetimi" şablonuyla aynı testleri denetletti; 20 testin 12'sinin dekor (assert'siz veya önemsiz) olduğu ortaya çıktı. Doğru soru, doğru cevabı getirdi.

Sık yapılan hatalar

  • Kapsamı kalite sanmak. Yüksek satır kapsamına güvenip mutasyon skoruna hiç bakmamak.
  • YZ'nin övgüsüne güvenmek. "Testlerin iyi mi" sorup olumlu cevabı güvence saymak.
  • Beklenen değeri koddan türetmek. Kendini doğrulayan, hatalı kodu onaylayan testler.
  • Önemsiz assert'lerle yetinmek. "null değil", "200 döndü" gibi gerçek kuralı doğrulamayan kontroller.
  • Hayatta kalan mutasyonları görmezden gelmek. Mutasyon raporundaki yakalanmayanları önemsememek.
  • Kritik kod için elle bile mutasyon denemesi yapmamak. Araç yoksa "kodu boz ve sına" adımını atlamak.

Özetle

Sahte-güven, testler yeşil diye yazılımın doğru olduğuna inanmaktır; oysa testler hiçbir şeyi doğrulamıyor olabilir. Bunu ölçmenin altın standardı mutasyon testidir: kodu kasten bozup testlerin yakalayıp yakalamadığını ölçmek. Mutasyon skoru, kapsam yüzdesinden çok daha dürüst bir kalite ölçüsüdür. YZ hem sahte-güven üretir hem de onu avlamada güçlü bir kırmızı takım olur — "bu testleri geçen bir hata üret" diye sorun. Testlerinizi test edin: gerçek assert, bağımsız beklenen değer, iş kuralı doğrulaması ve öldürülen mutasyonlar.

Uygulama görevi

Kendi projenizden iş kuralı içeren bir fonksiyon ve testlerini alın. Mümkünse bir mutasyon aracı (Stryker/Pitest/mutmut) çalıştırıp mutasyon skorunu ölçün; araç yoksa "elle mutasyon denetimi" şablonuyla en az 8 mutasyon üretip elle deneyin. Hayatta kalan her mutasyon için "hayatta kalan mutasyonu öldürme" şablonuyla yeni test yazın. Son olarak "kırmızı takım" şablonuyla YZ'nin testlerinizi kandıran bir kod üretip üretemediğini görün. Başlangıç ve bitiş mutasyon skorunuzu (veya yakalanan/toplam mutasyon oranını) raporlayın.

Kontrol listesi

  • [ ] Test kalitesini kapsamla değil, mutasyon skoruyla değerlendirdim.
  • [ ] Kritik kod için mutasyon testi (araçla veya elle) çalıştırdım.
  • [ ] Hayatta kalan her mutasyon için yeni test yazdım.
  • [ ] YZ'yi kırmızı takım olarak kullanıp testlerimin boşluklarını arattım.
  • [ ] YZ'nin "testlerin iyi" övgüsünü güvence olarak kabul etmedim.
  • [ ] Her testin gerçek assert, bağımsız beklenen değer ve iş kuralı doğruladığını denetledim.