---
title: 'Çoklu Ortam Testi'
source: 'https://academia.sh/tr/kurslar/python-projeleri/coklu-ortam-testi'
course: 'Python Projeleri: Paketleme ve Test'
language: tr
updated: '2026-08-17T18:10:32+00:00'
license: 'CC BY-SA 4.0'
---

# Çoklu Ortam Testi

Aynı yedi testlik takım üç yorumlayıcı, iki çözümleme ve üç sıra ekseninde 18 koşumda 4 ayrı karar verir; kilit dosyası koşumu 9'a ve kararı 3'e, düzenek 3'e ve 2'ye indirir, kalan iki karar ise gerçek ortam farkının kendisidir.

Önceki ders tek bir ortamda çalıştı. Ölçtüğü şey kaynağın kendisiydi: altı yazım, tek ağaç,
tek davranış. Kaynak metni hangi yorumlayıcıda okunursa okunsun aynı ağacı verir, bu yüzden
o ölçüm ortamdan bağımsızdı.

Testler için aynı şey söylenemez. Bir test yalnız kodu değil, kodun **içinde bulunduğu
düzeneği** çalıştırır: hangi yorumlayıcı, hangi bağımlılık kümesi, hangi sıra. Ortak
kurgunun beş testlik takımı yalnız sıraya göre bile ayrı karar veriyordu. Bu dersin sorusu o
gözlemi genişletir: **aynı takım kaç ortamda kaç ayrı karar verir, ve bu sayı hangi
kararlarla iner?**

## Ortam Kaç Eksenden Kurulur

"Ortam" tek bir şey değil, bir **eksenler çarpımıdır**. Bu ölçümde üç eksen vardır.

**Yorumlayıcı ekseni.** Üç kurgu yorumlayıcı — `Y1`, `Y2`, `Y3` — birer **yetenek
kümesiyle** modellenir. Gerçek sürüm numarası yazılmaz; yorumlayıcılar arasındaki fark,
bir yeteneğin bulunup bulunmamasına indirgenir. `Y1` `birlesim` yeteneğini taşımaz,
öbür ikisi taşır.

**Çözümleme ekseni.** Aynı bağımlılık bildirimi iki strateji ile çözülür: **en yeni** ve
**en eski uyumlu**. Ortak tanımın gösterdiği gibi bu, aynı bildirimden iki ayrı sürüm
kümesi çıkarır. Üçüncü bir seçenek kilit dosyasıdır ve stratejinin sonucu değiştirmesini
durdurur.

**Sıra ekseni.** Takım üç ayrı sırada koşturulur. Paylaşılan durumu kirleten bir test ile
kirlenmemiş ortam varsayan bir test aynı takımdadır; hangisinin önce koştuğu sonucu
değiştirir.

Takım yedi testliktir: ortak kurgunun beş testi, artı ortamı okuyan iki test. `yetenek`
testi yorumlayıcının yetenek kümesine bakar, `surum` testi çözümlenen `rapor` sürümünün en
az `1.1` olmasını ister. Beş testin davranışına dokunulmaz.

Bir hattın bu matrisi nasıl tanımlayacağı, hangi işin hangi çalıştırıcıda koşacağı ve
sonucun nereye raporlanacağı **Sürekli Tümleştirme ve Teslimat** kursunda işletim tarafında
kuruldu ve burada tekrarlanmaz. Bu derste hat yoktur; ölçülen tek şey **kaç ortamda kaç
ayrı karar** çıktığıdır.

## Matrisin Maliyeti

Eksenler çarpılır: üç yorumlayıcı, iki çözümleme, üç sıra — **18** koşum. Yedi testlik takım
her koşumda baştan çalıştığı için toplam **126** test çağrısı yapılır. Eksen sayısı
arttıkça bu sayı çarpımsal büyür; bir eksen daha eklemek koşum sayısını ikiye ya da üçe
katlar.

Buna karşın matrisin **verdiği bilgi** aynı hızda büyümez. Matris, ayrı karar üretmeyen
eksen noktaları da içerebilir; `Y2` ile `Y3` bu ölçümde aynı yetenek kümesini taşır ve
hiçbir koşumda birbirinden ayrılmaz. Ölçüm bunu doğrudan gösterir.

Bir eksenin matriste yer alması için iki koşul gerekir. **Kararı değiştirebilmelidir** —
değiştiremiyorsa koşum sayısını büyütür, bilgi eklemez. **Elenemez olmalıdır** — bir
yapılandırma kararıyla sabitlenebiliyorsa, matriste tutulması yerine sabitlenmesi gerekir.
Bu iki koşul bu dersin ölçtüğü şeyin tanımıdır: sıra ve çözümleme eksenleri birinci koşulu
sağlar ama ikinci koşulda düşer; yorumlayıcı ekseni ikisini de sağlar ve matriste kalır.

Süre burada da ölçülmez. Bir matrisin maliyeti, koşum ve çağrı sayısı olarak yazıldığında
yeniden üretilebilir kalır; aynı matris başka bir makinede aynı **126** çağrıyı yapar.
Ölçmenin neyi saydığını yazma kuralı bir önceki kursun kapanışında kurulmuştu ve bu kursta
da sürer.

Ölçümün varsayımları:

- **KY8** — Yorumlayıcılar kurgudur ve yalnız yetenek kümeleriyle ayrılır; gerçek sürüm
  numarası yazılmaz, yorumlayıcı gerçekleştirimi adlandırılmaz.
- **KY9** — Ortak tanımın beş testi aynen alınır; `kirleten` ve `bagimli` testlerinin
  davranışı değiştirilmez. Eklenen iki test paylaşılan duruma dokunmaz, yalnız ortamı okur.
- **KY10** — `surum` testi çözümlemeyi her çağrıda yeniden yapar; kilit seçildiğinde
  çözümleme yerine kilitteki küme okunur.
- **KY11** — Düzenek açıkken paylaşılan ortam **her testten önce** yeniden kurulur. Düzeneğin
  bu etkisi bu kursun düzenek ve parametreleme dersinde ölçüldü; burada bir **eleme aracı**
  olarak kullanılır, yeniden ölçülmez.
- **KY12** — Bir koşumun kararı, geçen test sayısıdır. İki koşum aynı sayıyı veriyorsa
  **bir** ayrı karar sayılır, düşen testlerin adları farklı olsa bile.
- **KY13** — Hiçbir süre ölçülmez. Matrisin maliyeti **koşum sayısı** ve **test çağrısı**
  olarak yazılır.
- **KY14** — Gerçek kurulum yapılmaz, gerçek paket indirilmez; yorumlayıcı ve bağımlılık
  kümesi tümüyle ders içinde modellenir.

## Ölçüm

```python
"""Coklu ortam testi: ayni takim kac ortamda kac ayri karar veriyor."""

DEPO = {"olcum": [(1, 0), (1, 1), (1, 2), (2, 0)],
        "rapor": [(0, 9), (1, 0), (1, 1)],
        "ortak": [(3, 0), (3, 1), (3, 2), (4, 0)]}
BILDIRIM = {"olcum": ((1, 0), (2, 0)), "rapor": ((1, 0), (2, 0)),
            "ortak": ((3, 0), (4, 0))}


def coz(strateji):
    secim = {}
    for paket in sorted(BILDIRIM):
        alt, ust = BILDIRIM[paket]
        adaylar = [s for s in DEPO[paket] if alt <= s < ust]
        secim[paket] = adaylar[-1] if strateji == "en yeni" else adaylar[0]
    return secim


KILIT = dict(coz("en yeni"))


class Ortam:
    def __init__(self):
        self.sayac = 0


def t_temiz_a(o, y, s):
    return True


def t_kirleten(o, y, s):
    o.sayac += 1
    return True


def t_bagimli(o, y, s):
    return o.sayac == 0


def t_temiz_b(o, y, s):
    return True


def t_temiz_c(o, y, s):
    return True


def t_yetenek(o, y, s):
    """Yorumlayicinin birlesim yetenegini ister."""
    return "birlesim" in YORUMLAYICI[y]


def t_surum(o, y, s):
    """Cozumlenen rapor surumunun en az 1.1 olmasini ister."""
    return (KILIT if s == "kilit" else coz(s))["rapor"] >= (1, 1)


TESTLER = [("temiz_a", t_temiz_a), ("kirleten", t_kirleten),
           ("bagimli", t_bagimli), ("temiz_b", t_temiz_b),
           ("temiz_c", t_temiz_c), ("yetenek", t_yetenek),
           ("surum", t_surum)]
SIRALAR = {"yazım sırası": [0, 1, 2, 3, 4, 5, 6],
           "bağımlı önce": [0, 2, 1, 3, 4, 5, 6],
           "ters": [6, 5, 4, 3, 2, 1, 0]}
YORUMLAYICI = {"Y1": {"a"}, "Y2": {"a", "birlesim"}, "Y3": {"a", "birlesim"}}
CAGRI = 0


def kosum(y, s, sira, duzenek=False):
    """Duzenek acikken paylasilan ortam her testten once yeniden kurulur."""
    global CAGRI
    o, gecen, dusen = Ortam(), 0, []
    for i in sira:
        ad, islev = TESTLER[i]
        if duzenek:
            o = Ortam()
        CAGRI += 1
        if islev(o, y, s):
            gecen += 1
        else:
            dusen.append(ad)
    return gecen, dusen


print(f"{'yorumlayıcı':<12s} {'çözümleme':<10s} {'sıra':<14s} {'geçen':>6s}  düşen")
karar = []
for y in YORUMLAYICI:
    for s in ("en yeni", "en eski"):
        for sad, sira in SIRALAR.items():
            gecen, dusen = kosum(y, s, sira)
            karar.append(gecen)
            print(f"{y:<12s} {s:<10s} {sad:<14s} {gecen:6d}  "
                  f"{','.join(dusen) or '-'}")
print(f"\n{len(karar)} koşum, {len(set(karar))} ayrı karar: {sorted(set(karar))}")
print(f"test çağrısı {CAGRI}")

print()
print(f"{'aşama':<34s} {'koşum':>6s} {'ayrı karar':>11s} {'çağrı':>6s}")
for ad, stratejiler, siralar, duzenek in (
        ("ham matris", ("en yeni", "en eski"), SIRALAR, False),
        ("kilit dosyasıyla", ("kilit",), SIRALAR, False),
        ("kilit ve düzenekle", ("kilit",), {"tek": SIRALAR["yazım sırası"]}, True)):
    CAGRI, sonuc = 0, []
    for y in YORUMLAYICI:
        for s in stratejiler:
            for sira in siralar.values():
                sonuc.append(kosum(y, s, sira, duzenek)[0])
    print(f"{ad:<34s} {len(sonuc):6d} {len(set(sonuc)):11d} {CAGRI:6d}  "
          f"{sorted(set(sonuc))}")

print()
for y in YORUMLAYICI:
    gecen, dusen = kosum(y, "kilit", SIRALAR["yazım sırası"], True)
    print(f"{y}: {gecen}/7 geçti, düşen: {','.join(dusen) or '-'}")
```

```
yorumlayıcı  çözümleme  sıra            geçen  düşen
Y1           en yeni    yazım sırası        5  bagimli,yetenek
Y1           en yeni    bağımlı önce        6  yetenek
Y1           en yeni    ters                6  yetenek
Y1           en eski    yazım sırası        4  bagimli,yetenek,surum
Y1           en eski    bağımlı önce        5  yetenek,surum
Y1           en eski    ters                5  surum,yetenek
Y2           en yeni    yazım sırası        6  bagimli
Y2           en yeni    bağımlı önce        7  -
Y2           en yeni    ters                7  -
Y2           en eski    yazım sırası        5  bagimli,surum
Y2           en eski    bağımlı önce        6  surum
Y2           en eski    ters                6  surum
Y3           en yeni    yazım sırası        6  bagimli
Y3           en yeni    bağımlı önce        7  -
Y3           en yeni    ters                7  -
Y3           en eski    yazım sırası        5  bagimli,surum
Y3           en eski    bağımlı önce        6  surum
Y3           en eski    ters                6  surum

18 koşum, 4 ayrı karar: [4, 5, 6, 7]
test çağrısı 126

aşama                               koşum  ayrı karar  çağrı
ham matris                             18           4    126  [4, 5, 6, 7]
kilit dosyasıyla                        9           3     63  [5, 6, 7]
kilit ve düzenekle                      3           2     21  [6, 7]

Y1: 6/7 geçti, düşen: yetenek
Y2: 7/7 geçti, düşen: -
Y3: 7/7 geçti, düşen: -
```

## On Sekiz Koşum, Dört Karar

Üst tablo aynı takımın on sekiz koşumunu yan yana koyuyor. Geçen test sayısı **4** ile **7**
arasında değişiyor; **4 ayrı karar** var.

Dördünü tek tek okumak, sayının nereden geldiğini gösterir. En kötü satır `Y1` /
`en eski` / `yazım sırası`: **4/7**, düşen üç test `bagimli`, `yetenek` ve `surum`. En iyi
satırlar `Y2` ve `Y3`'ün `en yeni` / `bağımlı önce` ve `ters` koşumları: **7/7**, düşen
yok.

Dikkat edilmesi gereken şey, aradaki farkın **üç ayrı kaynaktan** gelmesidir. `bagimli`
testinin düşmesi sıra ekseninden, `surum` testinin düşmesi çözümleme ekseninden, `yetenek`
testinin düşmesi yorumlayıcı ekseninden geliyor. Üçü aynı sütunda toplanıyor ve tek bir
sayıya — geçen test sayısına — karışıyor.

Bir raporda yalnız bu sayı görünseydi elde dört ayrı değer olurdu ve hiçbiri hangi eksenin
sorumlu olduğunu söylemezdi. `düşen` sütunu tam da bu yüzden var: **karar sayısı farkın
varlığını, düşen testin adı farkın kaynağını verir.** Matrisin bir eksenle daha büyütülmesi
ilk sayıyı büyütür, ikinciyi vermez.

## Aynı Sayı, Ayrı Neden

Üst tabloda **5** değeri beş ayrı satırda geçiyor ve düşen testler bu beş satırda üç ayrı
küme oluşturuyor: `bagimli` ile `yetenek`, `yetenek` ile `surum`, `bagimli` ile `surum`.
Aynı sayı, üç ayrı nedenle çıkıyor.

Bu, ölçümün en kolay yanlış okunan yeridir. İki koşumun aynı sayıyı vermesi, aynı durumda
olduklarını göstermez; yalnız **düşen test sayısının** eşit olduğunu gösterir. Karar
sayısını sayarken bu iki satırı bir sayıyoruz — varsayım bloğu bunu açıkça yazıyor — çünkü
ölçülen şey ayrı sonuç sayısıdır, ayrı neden sayısı değil. Ama bir arıza incelenirken
soru tersine döner ve nedeni ayırmak gerekir.

`ters` sırasındaki iki satır aynı ayrımın küçük bir örneğini taşıyor: `Y1` / `en eski` /
`ters` koşumunda düşen testler `surum,yetenek` sırasıyla, `bağımlı önce` koşumunda
`yetenek,surum` sırasıyla yazılıyor. Küme aynı, sıra ayrı — çünkü liste testlerin
koştuğu sırayla doluyor. Sayıya hiçbir etkisi yok, ama iki dökümü metin olarak
karşılaştıran bir araç bunları ayrı sayardı.

Buradan pratik bir sonuç çıkar: **koşum raporu yalnız sayıyı taşırsa, ayrı nedenler aynı
satırda toplanır.** Düşen testlerin adı raporda duruyorsa üç neden birbirinden ayrılabilir;
durmuyorsa matris on sekiz koşum yapmış olur ve elde dört sayı kalır. Matrisi genişletmenin
maliyeti çarpımsaldır, ondan alınan bilgi ise raporun ne taşıdığına bağlıdır.

## Eksenleri Elemek

Orta tablo elemenin üç aşamasını ölçüyor.

**Ham matris**: **18** koşum, **4** ayrı karar, **126** test çağrısı. Bu, hiçbir eksenin
sabitlenmediği durumdur.

**Kilit dosyasıyla**: çözümleme ekseni düşüyor, çünkü kilit stratejinin sonucu değiştirmesini
durduruyor. Koşum **9**'a, çağrı **63**'e, ayrı karar **3**'e iniyor. Kaybolan karar `4`;
`surum` testi artık hiçbir koşumda düşmüyor. Kilit çözümlemeyi ortadan kaldırmıyor —
kararı bir kez verdirip yazıya geçiriyor — ama ortam matrisinden bir ekseni **tümüyle**
çıkarıyor.

**Kilit ve düzenekle**: sıra ekseni de düşüyor. Koşum **3**'e, çağrı **21**'e, ayrı karar
**2**'ye iniyor. `bagimli` testi artık hiçbir sırada düşmüyor, çünkü paylaşılan ortam her
testten önce yeniden kuruluyor.

Geriye kalan **2** ayrı karar burada durur ve indirilemez. Alt satırlar bunu gösteriyor:
`Y1` **6/7**, `Y2` ve `Y3` **7/7**. Düşen tek test `yetenek`, ve düşmesinin nedeni bir
yapılandırma ayrıntısı değil, yorumlayıcının gerçekten bir yeteneği taşımamasıdır. Çoklu
ortam koşumunun aradığı fark tam olarak budur.

Elemenin sırası ara sayıları belirler, son sayıyı belirlemez. Düzenek kilitten önce
uygulansaydı orta satırdaki **3** yerine başka bir sayı görülürdü, çünkü o aşamada elenmiş
olan eksen başka olurdu. Elemenin her adımı bir ekseni tümüyle düşürür ve o eksenin karara
katkısını da beraberinde götürür; iki eksen de düşürüldüğünde hangi sırayla gelinirse
gelinsin geriye aynı **2** karar kalır. Ara sayılar yöntemin, son sayı ise ortamın
özelliğidir.

Buradan dersin kuralı çıkar: **çoklu ortam koşumu ortam kaynaklı farkı bulmak içindir;
yapılandırma kaynaklı fark önce elenmezse hangi eksenin sorumlu olduğu bilinemez.** On sekiz
koşumluk matris dört karar veriyordu ve bunların ikisi ortamla ilgili bile değildi. Eleme,
koşum sayısını altıda bire indirirken kaybettiği tek bilgi, zaten bu ölçümün konusu olmayan
bilgidir.

Son bir okuma matrisin genişliğiyle ilgilidir. Üç yorumlayıcı koşturuldu ama ayrı karar
**2** çıktı; `Y2` ile `Y3` hiçbir koşumda ayrılmadı, çünkü yetenek kümeleri aynı. Matrisin
bir noktası daha eklemek koşum ve çağrı sayısını doğrusal büyütür ama ayrı karar sayısını
**büyütmeyebilir**. Matrisin genişliği bir maliyet, ayrı karar sayısı ise bir kazançtır ve
ikisi aynı hızda artmaz.

## Özet

- Ortam tek bir şey değil, eksenler çarpımıdır; burada üç eksen **18** koşum ve **126** test
  çağrısı üretir.
- Aynı yedi testlik takım bu matriste **4 ayrı karar** verir (**4**, **5**, **6**, **7**);
  fark üç ayrı eksenden gelir ve tek bir sayıya karışır.
- Düşen testin adı farkın kaynağını verir: `bagimli` sıradan, `surum` çözümlemeden,
  `yetenek` yorumlayıcıdan.
- Kilit dosyası çözümleme eksenini düşürür — **9** koşum, **3** ayrı karar; düzenek sıra
  eksenini düşürür — **3** koşum, **2** ayrı karar.
- Kalan **2** karar indirilemez ve gerçek ortam farkıdır: `Y1` **6/7**, `Y2` ve `Y3`
  **7/7**. Üç yorumlayıcı koşturulmasına karşın ayrı karar sayısı ikidir; matrisin
  genişlemesi ayrı sonuç sayısını büyütmek zorunda değildir.

## Sonraki Adım

Bu ders takımı ortamdan ortama taşıdı ve her ortamda aynı kaynağın koştuğunu varsaydı. Bu
varsayım sessizdir ve sınanmadı: koşan şey gerçekten aynı kaynak mıydı? Bir proje
başkasının kullanımına verildiğinde kaynak doğrudan gitmez; bir **dağıtım biçimine**
paketlenir ve o paket açılarak kurulur. Sonraki ders bu adımı ölçer: aynı kaynaktan üretilen
dağıtım kaç ayrı içerik verir, hangi girdiler bu sayıyı birden büyütür ve neyi sabitlemek
onu bire indirir?
