Kod Kapsamının Açıklaması: Hat Kapsamı ve Şube Kapsamı ve %100’ün Gerçek Anlamı
Kapsam size testlerinizin hangi kodu çalıştırdığını söyler. Testlerin herhangi bir şeyi kontrol edip etmediğini size söylemez. Farkı göstermek için küçük bir modülü üç şekilde ölçtük.
- Kod kapsamı testler sırasında kodunuzun ne kadarının çalıştığını ölçer.
- Şube kapsamı hat kapsamından daha katıdır ve daha kullanışlıdır.
- Testimizde, hiçbir iddianın bulunmadığı bir paket hâlâ %100 kapsama ulaştı.
- Kalitenin kanıtı olarak değil, test edilmemiş kodu bulmak için kapsamı kullanın.
Bir ekip gururla %95 kod kapsamını rapor ediyor, ardından “kapsanan” bir satıra bir hata gönderiyor. Bu bir çelişki değil. Kapsam dar bir soruyu yanıtlıyor: testler bu kodu yürüttü mü? Sonucu kontrol edip etmedikleri tamamen farklı bir sorudur.
Python’u cover.py 7.17 ve pytest 9.2 ile kullandık. Aşağıdaki her sayı ve rapor kendi çalışmamıza aittir. Fikirler her dilde geçerlidir.
Kod kapsamı nedir?
Kod kapsamı, otomatik testleriniz çalışırken kodunuzun çalışan yüzdesidir. Bir araç, hangi satırların ve isteğe bağlı olarak hangi dalların yürütüldüğünü kaydeder ve ardından neyin kaçırıldığını bildirir.
En çok tersi durumda kullanışlıdır. Bir alandaki kapsama alanının düşük olması, size kesinlikle testlerin bu alanı uygulamadığını gösterir. Yüksek kapsama alanı size çok daha az şey anlatır.
Kapsam türleri
| Tür | Soru cevap verir |
|---|---|
| İşlev | Her işlev en az bir kez çağrıldı mı? |
| Satır (bildirim) | Her hat en az bir kez çalıştı mı? |
| Şube | Her biri if her iki yöne mi gitti; doğru ve yanlış? |
| Durum | Birleşik koşulun (a and b) her bir parçası her iki değeri de aldı mı? |
| MC/DC | Her koşul bağımsız olarak sonucu değiştirdi mi? Güvenlik açısından kritik yazılımlarda kullanılır. |
Her seviye bir üst seviyeden daha katıdır. Çoğu ekip hat ve şube kapsamını takip eder. Durum kapsamı ve MC/DC, takım desteğinin uzmanlaştığı havacılık ve otomotiv standartlarında görülür.
Ölçtüğümüz kod
def shipping_fee(total, is_member, express=False):
if total < 0:
raise ValueError("total cannot be negative")
fee = 0 if total >= 1000 else 50
if is_member:
fee = max(fee - 25, 0)
if express:
fee += 100
return fee
İlk test dosyamızda iki test vardı:
def test_regular_order():
assert shipping_fee(500, False) == 50
def test_member_express():
assert shipping_fee(500, True, express=True) == 125
Şube ölçümü açıkken çalıştırdık:
coverage run --branch -m pytest test_shipping.py
coverage report -m
Raporun okunması
Name Stmts Miss Branch BrPart Cover Missing
---------------------------------------------------------
shipping.py 9 1 6 1 87% 3
- Strmts 9, Miss 1: dokuz yürütülebilir ifade, biri hiç çalıştırılmadı.
- Şube 6, BrBölüm 1: üç
ifkarar, altı olası sonuç verir. Bir karar yalnızca tek bir yöne gitti. - Eksik 3: 3. satır,
raise ValueError, hiç çalışmadı. Hiçbir test negatif toplamı geçemedi.
Düzeltme, hata yolu için bir testtir. Ayrıca büyük bir sipariş için bir test de ekledik:
def test_free_over_1000():
assert shipping_fee(1000, False) == 0
def test_negative_total():
with pytest.raises(ValueError):
shipping_fee(-1, False)
Her iki dosyada da raporda %100 görüldü ve eksik satır veya kısmi dallanma yoktu. Hata yolları, klasik boşluk kapsamı bulgularıdır; bu nedenle, eşdeğerlik bölümleme gibi tekniklerle tasarlanan geçersiz giriş testleri onunla çok iyi eşleşir.
Raporun sakladığı şey
İlk rapora tekrar bakın. Sadece 3. satırın eksik olduğu söylendi. Ancak ilk iki testin her ikisi de toplam 500 adet kullandı; dolayısıyla 1000 veya üzeri siparişler için ücretsiz gönderim kuralı hiçbir zaman test edilmedi ve raporda bu kural işaretlenmedi.
Bunun nedeni fee = 0 if total >= 1000 else 50‘in tek satırda olmasıdır. cover.py satırlar arasındaki dalları ölçer, dolayısıyla tek bir satır içindeki koşullu ifade, yürütülen tek bir ifade olarak sayılır. Bu kuralda >= yerine > gibi bir hata olsaydı, ilk paket hala hiçbir ipucu olmadan %87 gösteriyordu. Onu yakalayan şey, sınır değeri analizinde açıklandığı gibi, bizzat sınırın testleridir.
Hiçbir kontrol olmadan %100 kapsam
Daha sonra, her yolu çağıran ancak hiçbir şey öne sürmeyen, kasıtlı olarak zayıf bir test yazdık:
def test_runs_everything_but_checks_nothing():
shipping_fee(500, True, express=True)
shipping_fee(1000, False)
shipping_fee(500, False)
try:
shipping_fee(-1, False)
except ValueError:
pass
shipping.py 9 0 6 0 100%
%100 hat ve şube kapsamına ulaştı. İşlev herhangi bir sayıyı döndürebilir ve bu test yine de başarılı olacaktır. Bu, kapsamın temel sınırıdır: doğrulamayı değil, yürütmeyi ölçer.
İpucu: Bir çekme isteğini incelerken yalnızca kapsam değişikliğini değil, iddiaları da okuyun. Anlamlı bir iddia olmadan kapsamı ekleyen bir test yalnızca yanlış güveni artırır.
Testlerin gerçekten hataları yakalayıp yakalamadığını ölçmek için mutasyon testini kullanın. Python için mutmut, Java için PIT veya JavaScript için Stryker gibi bir araç, kodunuzda >=‘yi >‘e çevirmek gibi küçük değişiklikler yapar ve bir testin başarısız olup olmadığını kontrol eder. İddiasız testimiz her mutasyonun hayatta kalmasına izin verecektir.
Hangi hedefi belirlemeli
Evrensel olarak doğru bir sayı yoktur. Pratik rehberlik:
- %100’ün peşinden koşmayın. Son yüzde birkaçı genellikle önemsiz kodları test etmek veya yalnızca çizgilere değinen testler yazmak anlamına gelir.
- Birçok ekip genel olarak kabaca %70 ila 85’i hedefliyor ve temel iş mantığına ilişkin beklentiler daha yüksek.
- Rakamı değil, trendi izleyin. Her yayında düşen kapsama alanı bir uyarı işaretidir.
- Eski kodun tamamını bir kerede zorlamak yerine, çekme isteklerinde yeni kodun kapsanmasını zorunlu kılın.
- Oluşturulan kod gibi önemli olmayan şeyleri açık kurallarla hariç tutun.
Goodhart yasası geçerlidir: Bir önlem hedef haline geldiğinde iyi bir önlem olmaktan çıkar. Zor hedefler, iddiasız örneğimiz gibi testleri teşvik eder.
Dile göre araçlar
| Dil | Ortak araçlar |
|---|---|
| Python | kapsama.py, pytest-cov |
| JavaScript / TypeScript | Jest ve Vitest’te yerleşik olarak İstanbul (nyc) |
| Java | JaCoCo |
| .NET | Yatak Örtüsü |
| Git | teste git - kapak |
| Raporlama | Codecov, SonarQube, Tulumlar |
CI’da kapsam
Kapsamı CI ardışık düzeninizin bir parçası olarak çalıştırın ve incelemecilerin hangi yeni satırların test edilmediğini görebilmesi için raporu yayınlayın. Coverage.py ile coverage report --fail-under=80 bir eşiğin altındaki derlemede başarısız oluyor. Herhangi bir eşiği makul düzeyde tutun ve bunu yeni koda ilişkin bir kuralla birleştirin; böylece tek bir büyük eski dosya her değişikliği engellemez.
Kapsamın ötesinde: sorulacak daha iyi sorular
- Testler kodun riskli ve sık değiştirilen kısımlarını kapsıyor mu?
- Sadece mutlu yol değil, sınırlar ve hata yolları da test ediliyor mu?
- Bu satır yanlış olsaydı test başarısız olur muydu?
- Testler her değişiklikte yürütülecek kadar hızlı ve kararlı mı?
Bunlar herhangi bir test stratejisine aittir. Kapsam yalnızca ilkinin yanıtlanmasına yardımcı olur.
Kodu hariç tutma ve HTML raporlarını okuma
Hata ayıklama yardımcıları veya yalnızca bir komut dosyası elle başlatıldığında çalışan bir blok gibi bazı kodlar doğrudan test etmeye değmez. kapsama.py, yorum içeren satırları hariç tutmanıza olanak tanır:
if __name__ == "__main__": # pragma: no cover
main()
Ayrıca yapılandırmada ölçülecek hariç tutmaları ve kaynak klasörleri de ayarlayabilirsiniz, örneğin pyproject.toml‘de:
[tool.coverage.run]
branch = true
source = ["shop"]
[tool.coverage.report]
show_missing = true
exclude_also = ["if TYPE_CHECKING:"]
Hariç tutmaları dikkatli kullanın ve bunları kod gibi gözden geçirin. Her biri bazı hatların asla kontrol edilmeyeceği kararıdır. Sadece sayıyı yükseltmek için test edilmesi zor bir hata işleyicisini hariç tutmak amacı boşa çıkarır.
Günlük işler için HTML raporu terminal tablosundan daha kullanışlıdır. coverage html‘i çalıştırın ve htmlcov/index.html‘yi açın. Her dosya yürütülen satırlar yeşil, kaçırılan satırlar kırmızı ve kısmi dallanmalar sarı renkte gösterilir, böylece hangi if‘ün asla başka bir yol izlemediğini bir bakışta görebilirsiniz. Pek çok editör kenar boşluğunun kapsamını da gösterebilir; bu da boşlukları daha sonra değil, siz kodu yazarken görünür hale getirir.
Yeniden düzenleme öncesi kapsam
Kapsam aynı zamanda yeniden düzenleme öncesinde bir güvenlik kontrolüdür. Bir modülü yeniden yapılandırmayı planlıyorsanız önce raporuna bakın. Kırmızı alanlarda davranış değiştiğinde sizi uyaracak testler yoktur; bu nedenle başlamadan önce mevcut davranışı yakalayan karakterizasyon testleri ekleyin. Bu şekilde kullanıldığında kapsama alanı hedef olmaktan çıkar ve pratik bir planlama aracı haline gelir.
Aynı rapor, bir hata üretime kaçtığında da yardımcı olur. Hatanın yaşadığı satırı bulun ve herhangi bir testin çalıştırılıp çalıştırılmadığını kontrol edin. Değilse, kapatmaya değer bir boşluk buldunuz. Eğer bir test bunu çalıştırdıysa, sorun zayıf bir iddiadır; iddiasızlık örneğimizin gösterdiği durum da tam olarak budur. Her iki cevap da size paketi nasıl geliştireceğinizi anlatıyor.
Son sözler
Kod kapsamı bir el feneridir, bir derece değil. Özellikle hata işleme olmak üzere hiçbir testin dokunmadığı kodu bulmak için dal kapsamını kullanın ve ardından gerçek iddialarda bulunan testler yazın. Çalışmamızdan bir sonucu hatırlıyorsanız, şunu yapın: Hiçbir şeyi kontrol etmeyen bir testle %100 kapsama ulaşıldı.
Sık sorulan sorular
Testte kod kapsamı nedir?
Otomatik testler yürütülürken satırlar, dallar veya koşullarla ölçülen, yürütülen kodun yüzdesidir. Testlerin doğrulayıp doğrulamadığını değil, hangi testlerin dokunduğunu gösterir.
Hat ve şube kapsama alanı arasındaki fark nedir?
Hat kapsama alanı her hattın çalışıp çalışmadığını kontrol eder. Şube kapsamı her kararın her iki yönde de gittiğini kontrol eder. Şube kapsamı, hat kapsamının kaçırdığı denenmemiş yolları bulur.
%100 kod kapsamı iyi mi?
Tek başına değil. Testimizde hiçbir iddiası olmayan bir paket %100’e ulaştı. Mükemmel bir sayı yerine önemli kod üzerinde anlamlı testler yapmayı hedefleyin.
İyi bir kod kapsama yüzdesi nedir?
Pek çok ekip genel olarak kabaca %70 ila 85’i hedefler ve daha fazlası kritik mantık üzerinedir. İddiaların eğilimi ve kalitesi, kesin sayıdan daha önemli.
Mutasyon testinin kapsamdan farkı nedir?
Mutasyon testi kodunuzu biraz değiştirir ve testin başarısız olup olmadığını kontrol eder. Testlerin kapsamın tespit edemediği hataları tespit edip etmediğini ölçer.
Öğrenmeye devam et
Test, WordPress veya SEO konusunda yardıma mı ihtiyacınız var?
Ekiplerin daha iyi yazılımlar sunmasına ve sitelerini büyütmesine yardımcı oluyoruz. Bize ne üzerinde çalıştığınızı söyleyin, biz de bir sonraki adım için net bir öneride bulunalım.
Daha fazla kılavuz test, yapay zeka ve modern geliştirme
Bu makaleyi beğendiniz mi? Bir konu seçin ve doğrudan en yeni eğitimlerimize geçin.
Yapay Zeka Halüsinasyonları Açıklandı: Dil Modelleri Neden İşleri Düzeltiyor ve Nasıl Azaltılabilir?
Yapay zeka halüsinasyonları açıkladı: ne olduklarını, dil modellerinin bunları neden ürettiğini, yaygın türlerini, temellendirme ve yönlendirmelerle…
Makaleyi okuyun →DevOpsAçıklanan Ortam Değişkenleri: .env Dosyaları, Sırlar ve Yapılandırma Doğru Yapıldı
Çalıştırdığımız Python örnekleriyle açıklanan ortam değişkenleri: bunları okumak ve ayarlamak, neden her değerin bir dize olduğu, .env dosyaları, sü…
Makaleyi okuyun →Yazılım geliştirmeAPI Hız Sınırlamasının Açıklaması: Algoritmalar, Başlıklar ve 429 Hatalarının Ele Alınması
API hızı sınırlaması, çalıştırdığımız bir simülasyonla açıklanmıştır: belirteç kümesi, sabit pencere, kayan pencere, 429 yanıt, hız sınırı başlıklar…
Makaleyi okuyun →Test otomasyonuPython'da alay etme: Unittest.mock, patch ve Testleri Yalan Yapan Hatalar
Unittest.mock ile Python'da alay etme, test edildi: Sahte ve dönüş_değeri, yan_etki, bir adın kullanıldığı yerde yama uygulama, spesifikasyon ve oto…
Makaleyi okuyun →Yazılım testiKod Kapsamının Açıklaması: Hat ve Şube Kapsamı ve %100'ün Gerçek Anlamı
Kod kapsamı gerçek bir kapsama.py çalışmasıyla açıklanmıştır: hat, şube ve durum kapsamı, bir raporun okunması, %100 kapsamın neden hâlâ hataları ka…
Makaleyi okuyun →Veritabanları ve SQLSQL'de DELETE vs TRUNCATE vs DROP: Farklılıklar, Geri Alma ve Her Biri Ne Zaman Kullanılmalı
DELETE vs TRUNCATE vs DROP test edilmiş SQL ile açıklandı: her birinin neyi kaldırdığı, geri aldığı, tetiklediği, kimlik sıfırlaması, hızı ve Postgr…
Makaleyi okuyun →Veritabanları ve SQLAçıklanan SQL Görünümleri: Örneklerle Tuzakları Oluşturun, Kullanın ve Önleyin
Çalıştırdığımız sorgularla açıklanan SQL görünümleri: görünüm oluşturma, canlı sonuçlar, sütunları gizleme, performans, güncellenebilir ve gerçekleş…
Makaleyi okuyun →Yazılım geliştirmeTypeScript Arayüzü ve Tür: Gerçek Farklılıklar, Derleyiciyle Test Edildi
TypeScript arayüzü ve türü, gerçek derleyiciyle kontrol edildi: her ikisinin de yapabileceği, yalnızca birinin yapabileceği, bildirim birleştirme, g…
Makaleyi okuyun →Yazılım geliştirmePython *args ve **kwargs'ın Açıklaması: Açık Örneklerle Esnek Fonksiyonlar
Python *args ve **kwargs çalıştırdığımız kodla açıklanmıştır: paketleme ve paketten çıkarma, parametre sırası, yalnızca anahtar kelime ve yalnızca k…
Makaleyi okuyun →Yazılım geliştirmePython Lambda İşlevleri: Söz Dizimi, Gerçek Kullanımlar ve Ne Zaman Kullanılmaması Gerektiği
Çalıştırdığımız kodla açıklanan Python lambda işlevleri: sözdizimi, anahtarla sıralama, harita ve filtre, kapatmalar, geç bağlama tuzağı ve normal b…
Makaleyi okuyun →Yapay zekâYapay Zeka Ajanları Nelerdir? Çalıştırabileceğiniz Basit Bir Aracı Döngüsüyle Nasıl Çalışırlar?
Yapay zeka ajanları nedir? Aracı döngüsüne, araçlara, belleğe ve korkuluklara ilişkin basit bir kılavuz, çalıştırdığımız küçük bir Python döngüsü, g…
Makaleyi okuyun →DevOpsİzleme ve Gözlemlenebilirlik: Günlükler, Metrikler ve İzlerle Gerçek Fark
İzleme ve gözlemlenebilirliğin açıklanması: bilinen ve bilinmeyen arızalar, günlükler, ölçümler ve izler, ödeme olayının gözden geçirilmesi, altın s…
Makaleyi okuyun →DevOpsDocker Birimleri ve Bağlama Bağlantıları: Konteyner Verilerini Doğru Şekilde Kalıcılaştırın
Docker birimleri ile bağlama bağlamaları arasındaki karşılaştırma açıklandı: kapsayıcı verilerinin neden kaybolduğu, adlandırılmış birimler, bağlama…
Makaleyi okuyun →Test otomasyonuTDD ve BDD: Temel Farklılıklar, Her İki Şekilde Geliştirilmiş Bir Özellik ve Her Birinin Ne Zaman Kullanılacağı
TDD ve BDD, her iki yönde de oluşturulmuş bir indirim özelliğiyle açıklandı: çalıştırdığımız kodla kırmızı-yeşil-refactor, Verilen-Ne Zaman-O Zaman …
Makaleyi okuyun →Yazılım geliştirmeGit merge vs rebase: farklar, örnekler ve hangisi ne zaman kullanılır
Git merge vs rebase; gerçek log çıktısı, karşılaştırma tablosu, rebase'in altın kuralı ve güvenli bir ekip iş akışıyla anlatılıyor.
Makaleyi okuyun →Yazılım geliştirmePython Liste Üreteci (List Comprehension): Sözdizimi, Örnekler ve Kaçınılacak Durumlar
Python list comprehension anlatımı: sözdizimi, filtreleme, if-else, iç içe döngüler, ölçülmüş süreler ve düz for döngüsünün daha iyi olduğu durumlar.
Makaleyi okuyun →Veritabanları ve SQLSQL JOIN Örneklerle Açıklama (Inner, Left, Right, Full)
SQL JOIN'leri örnek tablolar ve sorgularla adım adım öğrenin: INNER, LEFT, RIGHT, FULL, CROSS ve SELF; yaygın hatalar ve performans ipuçları.
Makaleyi okuyun →