---
title: 'Test Planları ve Kapsam'
source: 'https://academia.sh/tr/kurslar/ios-uretim/test-planlari-ve-kapsam'
course: 'Mimari, Test ve Yayınlama'
language: tr
updated: '2026-10-21T05:03:08+00:00'
license: 'CC BY-SA 4.0'
objectives:
    - 'Test planının test hedeflerini ve yapılandırmaları nasıl bir araya getirdiğini anlatır'
    - 'Kapsamın hangi satırın koştuğunu ölçtüğünü, sonucun doğruluğunu ölçmediğini gösterir'
    - 'Dalı koşturan ama sonucunu denetlemeyen testin kör kaldığını ölçerek kanıtlar'
    - 'Tek dile göre yazılmış beklentinin ikinci yapılandırmada doğru sürümü de reddettiğini gösterir'
---

# Test Planları ve Kapsam

Test planı yapılandırmaları ve kapsam raporunun okunması; koşan satır sayısını denetleyen kapsam kuralının ve iki dil yapılandırmasının doğru ve kusurlu sürümü ayırıp ayırmadığının ölçümü.

Önceki derste (Arayüz Testleri) bir düğmenin sonucunu denetleyen testin ayırdığını, yalnız varlığını denetleyen testin ayırmadığını gördük. Bu ders bir üst katmana çıkar: yüzlerce testi bir araya getiren plana ve o testlerin kodun ne kadarına dokunduğunu söyleyen kapsam raporuna.

Ölçü ekseni **ayrımdır**: aynı denetimi önce doğru, sonra kusurlu sürüme uygularız. **Ayıran** denetim doğru sürümde geçer, kusurlu sürümde kalır. **Kör** denetim ikisinde de geçer. **Gürültülü** denetim ikisinde de kalır. **Ters** denetim doğru sürümde kalır, kusurlu sürümde geçer. Çekirdek önceki derslerle aynıdır; her ders kendi başına çalıştığı için yeniden yazıyoruz.

```swift
// Separation.swift — bir denetimin dogru surumu kusurlu surumden ayirip ayirmadigini siniflandirir
struct Contrast<Output: CustomStringConvertible> {
    let label: String
    let correct: Output
    let faulty: Output
    let passesCorrect: Bool
    let passesFaulty: Bool

    var separation: String {
        switch (passesCorrect, passesFaulty) {
        case (true, false): return "ayiran"
        case (true, true): return "kor"
        case (false, false): return "gurultulu"
        case (false, true): return "ters"
        }
    }

    func describe() -> String {
        let onCorrect = passesCorrect ? "gecti" : "kaldi"
        let onFaulty = passesFaulty ? "gecti" : "kaldi"
        print("\(label) | dogru=\(correct)/\(onCorrect) kusurlu=\(faulty)/\(onFaulty) -> \(separation)")
        return separation
    }
}

func contrast<Output>(_ label: String, correct: Output, faulty: Output, check: (Output) -> Bool) -> Contrast<Output> {
    Contrast(label: label, correct: correct, faulty: faulty, passesCorrect: check(correct), passesFaulty: check(faulty))
}

func countSeparations(_ results: [String]) {
    for name in ["ayiran", "kor", "gurultulu", "ters"] {
        print("\(name): \(results.filter { $0 == name }.count)")
    }
}
```

`Contrast` iki çıktıyı ve denetimin her biri hakkındaki kararını tutar. `separation` etiketi bu iki karardan türer; `contrast` aynı kapanışı (closure) iki çıktıya uygular; `countSeparations` dört kategoriyi sayar. **Kural nedeni:** bir denetimin değeri geçmesinde değil, doğru ile kusurlu sürümü ayırmasında yatar.

## Test Planı

Bir uygulamanın birden çok test hedefi olabilir: birim testleri, arayüz testleri, başarım testleri. **Test planı** (test plan) bunları tek bir dosyada toplar. Plan hangi test hedeflerinin koşacağını, hangi testlerin atlanacağını ve testlerin hangi **yapılandırmalarla** koşacağını söyler. Yapılandırma, aynı testlerin değişen bir ayarla ikinci kez koşmasıdır: ekran dili, bölge, kapsam toplama, rastgele sıra gibi.

Plan bir JSON dosyasıdır ve geliştirme ortamı onu bir tablo olarak gösterir. Komut satırından `xcodebuild test` komutuna `-testPlan` bayrağıyla verilir; böylece aynı plan geliştirme makinesinde de otomatik denetim sunucusunda da aynı testleri koşar.

```json
{
  "configurations": [
    { "name": "Turkce", "options": { "language": "tr", "region": "TR" } },
    { "name": "Ingilizce", "options": { "language": "en", "region": "US" } }
  ],
  "defaultOptions": { "codeCoverage": true },
  "testTargets": [
    { "target": { "name": "ShopTests" } }
  ]
}
```

Bu bir yapılandırma dosyasıdır; ders onu çalıştırmaz. İki yapılandırma var: Türkçe ve İngilizce. `codeCoverage` seçeneği açıkken her koşumda hangi satırların çalıştığı kaydedilir. Plandaki her test iki yapılandırmada da koşar; yani aynı test iki kez sınanır ve iki ayrı sonucu olabilir.

## Kapsam Neyi Ölçer

**Kapsam** (code coverage) bir test takımı koşarken kodun hangi satırlarına ya da dallarına girildiğini sayar. Rapor satır satır "koştu" ya da "koşmadı" der ve oran verir. Bu bilgi değerlidir: hiç koşmayan bir satır kesinlikle denenmemiştir.

Ama kapsamın söylemediği bir şey var. Bir satırın koşması, sonucunun doğru olduğunu söylemez. Test fonksiyonu çağırır, dönen değere hiç bakmazsa satır koşmuş sayılır ve kapsam yükselir. Kapsam yüksekliğinin **güvence** olduğunu düşünmek buradan doğan yaygın bir yanılgıdır. Düşük kapsam bir eksiği gösterir; yüksek kapsam bir eksiğin olmadığını göstermez.

Aşağıdaki iki test bu farkı gösterir. İlki indirim dalını koşturur ama dönen değeri atar. İkincisi aynı dalı koşturur ve sonucu 180 ile karşılaştırır.

```swift
// indirim testleri — KAYNAK
import XCTest

final class PricingTests: XCTestCase {
    func testDiscountBranchRuns() {
        _ = price(100, coupon: true)
        _ = price(100, coupon: false)
    }

    func testDiscountedTotal() {
        XCTAssertEqual(price(200, coupon: true), 180)
    }
}
```

İki test de kapsam raporunda indirim satırını yeşil gösterir. Fakat yalnız ikincisi indirimin doğru hesaplanıp hesaplanmadığını sorar. İlki, fonksiyonun çökmediğini söylemekten fazlasını söylemez.

## İndirim Modeli

Aşağıdaki **model**, kapsam sayımının ve denetimin iki sürüme ne dediğini kurar; kapsam aracının kendisi değildir. Gerçek bir araç satır sayılarını derleyiciden alır. Model aynı işi küçük ölçekte yapar: işlevin her dalına bir işaret koyar ve koşan işaretleri bir kümede toplar. Üç işaret var: `giris`, `indirim` ve `duz`.

Doğru sürümde kuponlu sepetten yüzde on düşülür. Kusurlu sürümde bölme yüze çevrilmiştir ve yalnız yüzde bir düşülür. İkisi de aynı dallardan geçer; fark yalnız hesapta.

```swift
// Pricing.swift — indirim kuralinin dogru ve kusurlu surumu, kosan satir sayaci
func correctPrice(_ subtotal: Int, coupon: Bool, hits: inout Set<String>) -> Int {
    hits.insert("giris")
    if coupon {
        hits.insert("indirim")
        return subtotal - subtotal / 10
    }
    hits.insert("duz")
    return subtotal
}

func faultyPrice(_ subtotal: Int, coupon: Bool, hits: inout Set<String>) -> Int {
    hits.insert("giris")
    if coupon {
        hits.insert("indirim")
        return subtotal - subtotal / 100
    }
    hits.insert("duz")
    return subtotal
}

func executedCoverage(_ price: (Int, Bool, inout Set<String>) -> Int) -> String {
    var hits = Set<String>()
    _ = price(100, true, &hits)
    _ = price(100, false, &hits)
    return "\(hits.count) satirdan 3"
}

func discountedTotal(_ price: (Int, Bool, inout Set<String>) -> Int) -> Int {
    var hits = Set<String>()
    return price(200, true, &hits)
}
```

`executedCoverage` ilk testin modelidir: iki çağrıyı yapar, sonucu atar ve kaç işaretin koştuğunu yazar. `discountedTotal` ikinci testin modelidir: aynı dalı koşturur ve sonucu döndürür. Böylece iki denetimi yan yana koyabiliriz. Kapsam denetimi "üç satırdan üçü koştu mu" sorusudur; sonuç denetimi "toplam 180 mi" sorusudur.

```swift
// main.swift — kapsam denetimi ve sonuc denetimi
let coverage = contrast("kapsam-denetimi", correct: executedCoverage(correctPrice), faulty: executedCoverage(faultyPrice), check: { $0 == "3 satirdan 3" }).describe()
let outcome = contrast("indirim-sonucu", correct: discountedTotal(correctPrice), faulty: discountedTotal(faultyPrice), check: { $0 == 180 }).describe()

countSeparations([coverage, outcome])
```

```
kapsam-denetimi | dogru=3 satirdan 3/gecti kusurlu=3 satirdan 3/gecti -> kor
indirim-sonucu | dogru=180/gecti kusurlu=198/kaldi -> ayiran
ayiran: 1
kor: 1
gurultulu: 0
ters: 0
```

`kapsam-denetimi` kör: iki sürümde de üç satırdan üçü koştu ve kapsam eşiği geçti. Kusurlu sürümün kapsamı doğru sürümle aynıdır, çünkü kusur hangi satırın koştuğunda değil, o satırın ne hesapladığındadır. `indirim-sonucu` ayıran: doğru sürüm 180, kusurlu sürüm 198 verir ve denetim yalnız 180'i kabul eder.

Bu iki satır tek başına bir kapsam eşiği kararını sorgular. Bir takım "kapsam yüzde yüz olmadan birleştirme yok" kuralı koyduğunda, kusurlu sürüm bu kuralı geçer. Kural eksik testleri yakalar ama yanlış testleri yakalamaz.

**TS1.** Model üç işaretli tek bir işlevi sayar. Gerçek kodda binlerce satır ve dal vardır; ama tek bir işlevdeki fark, büyük bir tabloda da aynı biçimde gizlenir.

**TS2.** Kapsam denetimi burada satır işaretlerine bakar. Dal kapsamı ya da koşul kapsamı daha ince ölçer, ama onlar da hesabın doğruluğunu ölçmez.

## Kapsam Eşiği Nasıl Kullanılır

Kapsamın işe yarayan kullanımı bir tabandır, hedef değildir. Düşük kapsamlı bir dosya, hiç denenmemiş kodu gösterir; oraya test yazmak sonuç denetimi eklemenin başlangıcıdır. Yüksek kapsam ise bir sonuç değildir. Kapsamı yükseltmek için iddiasız testler yazmak ölçüyü bozar: sayı artar, güvence artmaz.

Bu yüzden bir test kodu gözden geçirilirken iki soru sorulur. Birincisi, test hangi satırlara giriyor. İkincisi, test hangi sonuçları denetliyor. Kapsam yalnız birinciyi cevaplar. İkincisi için aynı testin kusurlu sürüme uygulanmış hâline bakmak gerekir; bu dersin ayrım ölçüsü tam olarak onu yapar.

Bir de yanlış güven sorunu var. Ekipler çoğu zaman kapsam yüzdesini bir kalite göstergesi gibi panoya koyar. Gösterge yükseldikçe ekip testlerin yeterli olduğuna inanır ve yeni test yazma çabası düşer. Kapsamın gerçek işlevi, testlerin hiç dokunmadığı kod parçalarını görünür kılmaktır.

## Yapılandırmalar ve Beklenti

Test planının ikinci işlevi yapılandırmadır. Aynı test iki dilde koşar. Para tutarı Türkçe bölgede `180,00`, İngilizce bölgede `180.00` biçiminde yazılır; tarih biçimi de benzer biçimde değişir. Bir test beklenen metni yalnız bir dile göre yazdıysa, öbür yapılandırmada doğru sürüm bile kalır.

Modelde biçimlendirme gerçek bir biçimlendirici değil, iki dil için sabit bir kuraldır: Türkçede ondalık ayırıcı virgül, İngilizcede nokta. Gerçek bir uygulamada bu iş platformun biçimlendiricisine bırakılır.

## Sınırlayıcı Ölçüm

Aşağıdaki ölçüm `indirim-sonucu` denetiminin metin biçimini iki yapılandırmada uygular. Beklenen metin `180,00` olarak Türkçe yapılandırmaya göre yazılmıştır. İki sürüm de her yapılandırmada ayrı ayrı biçimlendirilir.

```swift
// main.swift — ayni beklenti, iki yapilandirma
func formattedTotal(_ total: Int, language: String) -> String {
    language == "tr" ? "\(total),00" : "\(total).00"
}

let correctTotal = discountedTotal(correctPrice)
let faultyTotal = discountedTotal(faultyPrice)

let turkish = contrast("tr-yapilandirmasi", correct: formattedTotal(correctTotal, language: "tr"), faulty: formattedTotal(faultyTotal, language: "tr"), check: { $0 == "180,00" }).describe()
let english = contrast("en-yapilandirmasi", correct: formattedTotal(correctTotal, language: "en"), faulty: formattedTotal(faultyTotal, language: "en"), check: { $0 == "180,00" }).describe()

countSeparations([turkish, english])
```

```
tr-yapilandirmasi | dogru=180,00/gecti kusurlu=198,00/kaldi -> ayiran
en-yapilandirmasi | dogru=180.00/kaldi kusurlu=198.00/kaldi -> gurultulu
ayiran: 1
kor: 0
gurultulu: 1
ters: 0
```

Türkçe yapılandırmada denetim ayırır. İngilizce yapılandırmada aynı denetim gürültülü olur: doğru sürüm de `180.00` ürettiği için kalır. Plan iki yapılandırmayı birlikte koştuğunda rapor kırmızıdır ve kırmızıya sebep kusur değildir. Takım bu kırmızıyı bir süre sonra alışılmış görür ve gerçek bir kusur çıktığında onu da aynı alışkanlıkla geçer.

Çözüm beklentiyi dile bağlı yazmamaktır: ya beklenen metin yapılandırmanın diline göre üretilir ya da denetim metne değil sayısal değere bakar. Bu ölçüm yalnız iki yapılandırmayı karşılaştırır; ikisi de aynı kusuru taşıyan iki sürümle koşar.

**TS3.** Gerçek bir kapsam raporunun yüzdesini bu dersin hiçbir yerinde ölçmedik. Model koşan işaretleri kendisi sayar; yüzde bir ürün çıktısıdır ve bu dersin ölçüsü değildir.

**TS4.** Modeldeki biçimlendirme iki dil için sabit bir kuraldır. Gerçek biçimlendirici daha çok bölge ve para birimi ayrıntısı taşır.

## Sık Yapılan Hatalar

- Kapsam yüzdesini kalite göstergesi saymak. Yüzde, sonucun doğruluğunu söylemez.
- Kapsamı yükseltmek için sonucu denetlemeyen testler yazmak.
- Beklenen metni tek dile göre yazıp planı iki dille koşmak. İkinci yapılandırma sürekli kırmızı kalır.
- Yapılandırmadaki kırmızıyı alışılmış sayıp bakmamak.
- Plana her testi ve her yapılandırmayı eklemek. Plan hızlı kalmazsa takım onu koşmaz.

## Özet

- Test planı test hedeflerini ve yapılandırmaları tek dosyada toplar; aynı test her yapılandırmada ayrı koşar.
- Kapsam hangi satırın koştuğunu sayar, sonucun doğruluğunu sormaz.
- İki denetimden biri kör, biri ayıran çıktı: kapsam denetimi iki sürümde de geçti, sonuç denetimi yalnız doğru sürümde geçti.
- Beklenti Türkçe biçime göre yazılınca aynı denetim ikinci yapılandırmada gürültülü oldu.
- Kapsam bir tabandır; eksik testi gösterir, yanlış testi göstermez.
- Bu dersin ayrımı: **kör**.

## Sonraki Adım

Testler kodun doğruluğunu sınar; hızını sınamaz. Sıradaki derste Profil Çıkarma Araçları, bir liste hücresinin her çizimde yaptığı işi sayacak ve iş miktarına bakan denetimin ne zaman ayırdığını ölçecek.
