İçeriğe geç
academia.sh

Ders 06 / 14

Düzenek ve Parametreleme

Beş testlik takım yazım sırasında 4/5, öbür iki sırada 5/5 geçer ve sıraya göre 2 ayrı karar verir; düzenek paylaşılan durumu her testte yeniden kurduğunda sayı 1'e iner, oturum düzeyinde kurulduğunda yine 1'e iner ama bu kez 4/5'te.

İçindekiler

Önceki ders keşif kuralının hangi testlerin koşacağını belirlediğini ölçtü: aynı dosya üç kuralda 3, 0 ve 4 test buldu ve rapor üçünde de aynı kaldı. Orada testler birbirinden bağımsızdı; her biri işlevi çağırıyor, dönen değeri karşılaştırıyor ve arkasında hiçbir iz bırakmıyordu.

Gerçek takımlar böyle değildir. Testlerin çoğu bir hazırlık ister: bir nesne kurulur, bir dizin açılır, bir sayaç sıfırlanır. Bu hazırlık paylaşıldığında testler birbirinin komşusu olur — ve komşuluk bir sıra doğurur. Bu dersin sorusu şudur: aynı takım, koşum sırası değiştiğinde kaç ayrı karar verir, ve bu sayıyı ne tekleştirir?

Paylaşılan Durum Sırayı Anlamlı Kılar

Ortak kurgunun beş testlik takımı bunun en yalın modelidir. Beş test tek bir ortam nesnesi üzerinde çalışır. Üçü ortama dokunmaz ve her koşulda geçer. Biri ortamı kirletir: bir sayacı bir artırır ve yine de geçer. Biri ise ortamın kirlenmemiş olduğunu varsayar; sayaç sıfırsa geçer, değilse düşer.

Beş testin hiçbiri tek başına kusurlu değildir. Kirleten test kendi işini yapar, bağımlı test de kendi işini yapar. Kusur ikisinin birlikte ve belli bir sırada koşmasındadır. Yazım sırasında kirleten test bağımlı testten önce çağrılır ve bağımlı test düşer; bağımlı testi öne alan sırada ve ters sırada ise bağımlı test önce çağrılır ve geçer.

Bu, Yazılım Kalitesi ve Test müfredatının Birim Testi ve Test Odaklı Geliştirme kursunda “hızlı ve bağımsız testler” başlığı altında kuram olarak kurulmuştu. Burada kuram tekrarlanmıyor; ölçülen şey aynı takımın kaç ayrı karar verdiğidir.

Sırayı Kim Belirler

Sıranın hiçbir teste yazılı olmaması bu ölçümün çıkış noktasıdır. Testlerin çağrılma düzeni koşucunun bir kararıdır ve bu karar en az dört yerden gelir.

Birincisi keşif düzenidir: koşucu dosyaları hangi sırayla topladıysa testler de o sırayla koşar, ve dosya adlarının sıralanışı bir dosyanın yeniden adlandırılmasıyla değişir. İkincisi seçim: yalnız düşen testleri ya da yalnız belli bir etiketi koşturmak, kalanları aradan çıkarır ve geri kalanların komşuluğunu değiştirir. Üçüncüsü dağıtım: testler birden çok işçiye bölündüğünde her işçi kendi alt kümesini kendi sırasıyla koşturur ve bölünmenin nasıl yapıldığı işçi sayısına bağlıdır. Dördüncüsü ise bilerek karıştırma: kimi kurulum sırayı her koşumda yeniden karar verilen bir değere bağlar, çünkü sıra bağımlılığını erken görmek ister.

Dördünün ortak yanı şudur: hiçbiri projenin kaynak dosyalarında yazılı değildir. Sıra, önceki dersteki keşif kuralıyla aynı sınıfa girer — kararın kodun dışında duran parçası. Bu dersin ölçümü de tam olarak o parçayı değiştirip sonucu okuyor: üç sıra, aynı beş test.

Düzenek: Hazırlığı Testten Çıkarmak

Düzenek (fixture), bir testin ihtiyaç duyduğu hazırlığı testin gövdesinden çıkaran ve çerçevenin çağırdığı bir birimdir. Testin kendisi ortamı kurmaz; düzenek kurar ve testin eline hazır verir. Bu, tekrarı azaltmanın yanında ikinci ve daha önemli bir şey yapar: hazırlığın ne zaman yapılacağını açık bir karara dönüştürür.

Bu karara düzeneğin kapsamı denir ve ölçümde üç değer alıyor.

Düzeneksiz. Ortam bir kez kurulur ve beş test onu paylaşır. Kirleten testin bıraktığı iz, kendisinden sonra koşan her teste görünür.

Her testte. Düzenek her testin öncesinde ortamı yeniden kurar. Kirleten testin izi bir sonraki teste ulaşmaz.

Oturum düzeyinde. Düzenek koşum oturumunun başında bir kez kurulur ve bütün testler, bütün koşumlar boyunca aynı nesneyi paylaşır. Bu kapsam pahalı hazırlıklar için seçilir — kurulumu ağır olan bir kaynak her testte yeniden kurulmasın diye.

Üç kapsamın da geçerli kullanımı vardır; ölçüm hangisinin “doğru” olduğunu değil, her birinin ayrı karar sayısına ne yaptığını veriyor.

Düzeneğin ikinci yarısı toplamadır: kurulan şeyin geri alınması. Bellekteki bir nesne için toplama gerekmez, yeni nesne eskisinin yerini alır ve eskisi kendiliğinden düşer. Bir dosya, bir dizin ya da bir bağlantı için ise toplama açıkça yazılır ve testin düşmesi durumunda da çalışması gerekir; bu, Python Temelleri kursunda kurulan bağlam yöneticisi protokolünün doğrudan uygulandığı yerdir. Toplaması eksik bir düzenek, paylaşımı ortadan kaldırdığını sanırken kalıntı bırakır ve ölçüm yine sıraya bağlı hale gelir.

Parametreleme: Aynı Gövde, Ayrı Girdi

Aynı iddiayı birden çok girdiyle sınamanın iki yolu vardır. Birincisinde girdiler tek bir testin içinde bir döngüye konur; ikincisinde her girdi ayrı bir test olur ve gövde paylaşılır. İkinciye parametreleme (parametrisation) denir.

Parametrelemenin düzenekle ortak bir yanı vardır: ikisi de tekrarı testin gövdesinden çıkarır. Ayrıldıkları nokta ise neyi çıkardıklarıdır. Düzenek hazırlığı çıkarır ve testler arasındaki paylaşımı yönetir; parametreleme girdiyi çıkarır ve tek bir gövdeyi birden çok duruma çoğaltır. Bu yüzden ikisi birbirinin yerine geçmez, birlikte kullanılır: parametrelenmiş her durum kendi düzeneğiyle koşar.

Fark testler geçerken görünmez. İkisi de aynı iddiayı aynı girdilerle sınar ve ikisi de yeşil rapor verir. Fark bir girdi düştüğünde ortaya çıkar: döngülü yazımda ilk sapma testi düşürür ve döngü orada durur, dolayısıyla kalan girdiler hiç denenmez. Rapor tek bir satır taşır ve o satırda testin adı yazar — hangi girdinin düştüğü değil. Parametrelenmiş yazımda ise her girdi kendi adıyla koşar; düşen girdi raporda adıyla görünür ve öbürleri koşmaya devam eder.

Ölçümün Varsayımları

  • PT9 — Beş testlik takım ve üç sıra ortak tanımdan alınır; TESTLER listesinin ve testlerin davranışı değiştirilmez. Ders yalnız düzenek kapsamı ekler.
  • PT10 — Kâhin kurgunun kendisidir: beş testin beşinin de temiz bir ortamda geçtiğini biz yazdığımız için biliyoruz. Doğru karar her sırada 5/5’tir.
  • PT11 — Üç sıra denenir: yazım sırası, bağımlı testi öne alan sıra ve ters sıra. Sıra listesi testlerin dizinlerinden oluşur ve hiçbir teste yazılı değildir.
  • PT12 — Düzeneksiz kapsamda ortam her koşumun başında bir kez kurulur; koşum içinde yeniden kurulmaz.
  • PT13 — Her testte kurulan kapsamda ortam, sıradaki her testin çağrılmasından hemen önce yeniden kurulur.
  • PT14 — Oturum düzeyinde kurulan kapsamda ortam üç koşumun tamamı için bir kez kurulur; koşumlar arasında da taşınır.
  • PT15 — Ayrı karar sayısı, üç sıranın verdiği geçen test sayılarının birbirinden farklı olanlarının sayısıdır.
  • PT16 — Parametreleme ölçümünde sınanan iddia şudur: her sıra 5/5 vermelidir. Bu iddia kâhinden gelir ve düzeneksiz takımda yazım sırasında yanlışlanır.
  • PT17 — Döngülü yazım ilk sapmada döner; parametrelenmiş yazım üç sırayı da koşturur. Süre ölçülmez, sayılan şey koşan sıra ve rapor satırı sayısıdır.
  • PT18 — Rapor satırı, çerçevenin sonuç listesine yazdığı kayıt sayısıdır; koşmayan girdi rapora hiç girmez.

Ölçüm

"""Duzenek ve parametreleme: paylasilan durumu kim, ne zaman kuruyor.

Bolum 1 - uc sira, uc duzenek rejimi.
Bolum 2 - ayni uc sira tek testte ve parametrelenmis testte.
"""


class Ortam:
    """Testlerin paylastigi durum."""

    def __init__(self):
        self.sayac = 0


def t_temiz_a(o):
    return True


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


def t_bagimli(o):
    return o.sayac == 0


def t_temiz_b(o):
    return True


def t_temiz_c(o):
    return True


TESTLER = [("temiz_a", t_temiz_a), ("kirleten", t_kirleten),
           ("bagimli", t_bagimli), ("temiz_b", t_temiz_b), ("temiz_c", t_temiz_c)]

SIRALAR = {"yazım sırası": [0, 1, 2, 3, 4],
           "bağımlı önce": [0, 2, 1, 3, 4],
           "ters": [4, 3, 2, 1, 0]}


def kosum(sira, rejim="düzeneksiz", oturum=None):
    """Duzenek kapsami: hic, her testte yeniden, ya da oturumda bir kez."""
    o = oturum if rejim == "oturum düzeyinde" else Ortam()
    gecen = 0
    for i in sira:
        if rejim == "her testte":
            o = Ortam()
        _, islev = TESTLER[i]
        if islev(o):
            gecen += 1
    return gecen, len(sira)


print(f"{'düzenek kapsamı':<18s} " + " ".join(f"{ad:>13s}" for ad in SIRALAR)
      + "  ayrı karar")
for rejim in ("düzeneksiz", "her testte", "oturum düzeyinde"):
    oturum, gecenler = Ortam(), []
    for sira in SIRALAR.values():
        gecenler.append(kosum(sira, rejim, oturum)[0])
    print(f"{rejim:<18s} " + " ".join(f"{g:>11d}/5" for g in gecenler)
          + f" {len(set(gecenler)):12d}")

print()


def tek_test():
    """Uc sirayi tek govdede, tek dongude dener; ilk sapmada doner."""
    kosulan = 0
    for ad, sira in SIRALAR.items():
        kosulan += 1
        gecen, toplam = kosum(sira)
        if gecen != toplam:
            return [("üç sıra", "düşen")], kosulan
    return [("üç sıra", "geçen")], kosulan


def parametreli_test():
    """Her sira ayri bir testtir; ucu de kosar."""
    rapor, kosulan = [], 0
    for ad, sira in SIRALAR.items():
        kosulan += 1
        gecen, toplam = kosum(sira)
        rapor.append((ad, "geçen" if gecen == toplam else "düşen"))
    return rapor, kosulan


print(f"{'yazım':<16s} {'rapor satırı':>12s} {'koşan sıra':>11s} "
      f"{'düşen olarak adlandırılan':>26s}")
satir, kosan = [], []
for ad, islev in (("tek test", tek_test), ("parametrelenmiş", parametreli_test)):
    rapor, kosulan = islev()
    dusen = [r[0] for r in rapor if r[1] == "düşen"]
    satir.append(len(rapor))
    kosan.append(kosulan)
    print(f"{ad:<16s} {len(rapor):12d} {kosulan:11d} "
          f"{(dusen[0] if dusen else '-'):>26s}")
print(f"aynı üç sıra: rapor satırı {len(set(satir))}, koşan sıra {len(set(kosan))} "
      f"ayrı sonuç; düşen karar ikisinde de 1")
düzenek kapsamı     yazım sırası  bağımlı önce          ters  ayrı karar
düzeneksiz                   4/5           5/5           5/5            2
her testte                   5/5           5/5           5/5            1
oturum düzeyinde             4/5           4/5           4/5            1

yazım            rapor satırı  koşan sıra  düşen olarak adlandırılan
tek test                    1           1                    üç sıra
parametrelenmiş             3           3               yazım sırası
aynı üç sıra: rapor satırı 2, koşan sıra 2 ayrı sonuç; düşen karar ikisinde de 1

İki Ayrı Karar ve Tekleşmenin İki Yolu

İlk satır kursun dördüncü okumasını ödüyor. Düzeneksiz takım yazım sırasında 4/5, bağımlı testi öne alan sırada 5/5, ters sırada 5/5 geçiyor — 2 ayrı karar. Beş testin kodu hiç değişmedi; değişen tek şey çağrılma sırası oldu. Aynı girdi, aynı kod, iki ayrı sonuç.

Bu sayının pratikteki karşılığı şudur: böyle bir takım koşumların bir kısmında yeşil, bir kısmında kırmızı olur ve kırmızı olduğunda düşen test kusurun bulunduğu test değildir. Rapor bagimli testini gösterir, oysa ortamı kirleten kirleten testidir. Sıra bağımlılığı tanıyı yanlış yere taşır.

İkinci satır düzeneğin ödediğini veriyor. Ortam her testin öncesinde yeniden kurulduğunda üç sıra da 5/5 veriyor ve sayı 1 ayrı karara iniyor. Kirleten test yine sayacı artırıyor, ama artırdığı nesne bir sonraki teste ulaşmıyor. Düzenek kusuru düzeltmedi — kusur zaten testlerde değildi — paylaşımı ortadan kaldırdı.

Üçüncü satır ölçümün asıl uyarısıdır. Oturum düzeyinde kurulan düzenek de sayıyı 1 ayrı karara indiriyor, ama bu kez 4/5’te. Kirlilik ilk koşumda birikiyor ve sonraki koşumlara da taşınıyor; bağımlı test artık hiçbir sırada geçmiyor. Sonuç kararlı hale geldi ve kararlı hale geldiği değer yanlış.

Buradan çıkan cümle bu dersin ölçü ekseninin en keskin ifadesidir: ayrı sonuç sayısının 1’e inmesi, inilen sonucun doğru olduğu anlamına gelmez. Yeniden üretilebilirlik doğruluğun yerine geçmez; yalnız doğruluğun tartışılabilir olmasının önkoşuludur. Bir takım her koşumda aynı yanlış cevabı veriyorsa yeniden üretilebilirdir ve yine de kusurludur.

İkinci ve üçüncü satırı ayıran şey de bu yüzden kapsamın adı değil, kurulumun hangi kararı verdiğidir. İkisi de tek bir sayı üretir; biri kirliliği hiç doğmadan keser, öbürü kirliliği kalıcı hale getirir. Bir takımın sıra bağımlılığından kurtulduğunu gösteren şey, ayrı karar sayısının 1 olması değil, o tek kararın kâhinle uyuşmasıdır — ve kâhin, ortak kurguda beş testin beşinin temiz ortamda geçtiğini söylüyor.

Bir uyarı da tersi yönde geçerlidir. Üç sıra denendiği için burada 2 ayrı karar görülebildi; tek bir sıra koşturulsaydı takım ya hep 4/5 ya hep 5/5 verirdi ve sıra bağımlılığı hiç görünmezdi. Sıra bağımlılığının ölçülebilmesinin koşulu, sıranın birden çok değer alacak biçimde koşturulmasıdır.

Rapor Satırı ve Koşan Girdi

Alt tablo parametrelemenin ödediğini veriyor. Üç sıra tek bir testin içinde denendiğinde koşucu 1 rapor satırı yazıyor ve o satırda testin adı — “üç sıra” — duruyor. Hangi sıranın düştüğü raporda yok; ayrıca ilk sapmada döndüğü için 1 sıra koşuyor ve kalan ikisi hiç denenmiyor. Bu ikinci nokta ilkinden ağırdır: rapor yalnız eksik bilgi vermiyor, ölçüm de eksik yapılıyor.

Parametrelenmiş yazımda aynı üç sıra 3 rapor satırı üretiyor ve 3 sıra koşuyor. Düşen satır adıyla görünüyor: “yazım sırası”. Öbür iki sıra koşmaya devam ettiği için raporu okuyan kişi kusurun üç sıranın hepsinde mi yoksa yalnız birinde mi olduğunu görebiliyor — ve bu ayrım tanıyı doğrudan kirleten testine götürüyor.

İki yazımın düşen karar sayısı aynı: ikisi de takımı kırmızı yapıyor. Ayrı olan şey raporun taşıdığı bilgi ve gerçekten koşan girdi sayısı. Parametreleme testin kararını değiştirmez, kararın çözünürlüğünü artırır.

Bu ayrımın bir bedeli de vardır ve saklanmamalıdır. Parametrelenmiş bir takımda test sayısı girdi sayısıyla birlikte büyür; on girdi on test demektir ve bu on test raporda on satır kaplar. Döngülü yazım tek satırla yetinir. Yani parametreleme, tanı bilgisini rapor hacmiyle satın alır. Ölçümün söylediği şey hangisinin seçileceği değil, seçimin neyi değiştirdiğidir: rapor satırı 2 ayrı sonuç, koşan sıra 2 ayrı sonuç, düşen karar 1.

Özet

  • Paylaşılan durum, testin doğruluğunu komşusuna bağlar; beş testin hiçbiri tek başına kusurlu değilken takım sıraya göre 2 ayrı karar verir: yazım sırasında 4/5, öbür iki sırada 5/5.
  • Düzenek hazırlığı testten çıkarır ve asıl kararı görünür kılar: hazırlık ne zaman yapılacak. Bu karara düzeneğin kapsamı denir.
  • Ortam her testte yeniden kurulduğunda üç sıra da 5/5 verir ve sayı 1 ayrı karara iner; düzenek kusuru düzeltmez, paylaşımı ortadan kaldırır.
  • Oturum düzeyinde kurulan düzenek de sayıyı 1’e indirir ama 4/5’te; ayrı sonuç sayısının tekleşmesi, tekleşilen sonucun doğru olduğunu söylemez.
  • Parametreleme kararı değiştirmez, çözünürlüğünü artırır: aynı üç sıra tek testte 1 rapor satırı ve 1 koşan sıra, parametrelenmiş yazımda 3 ve 3 verir.

Sonraki Adım

Düzenek paylaşılan durumu her testte yeniden kurarak sayıyı tekleştirdi — ama bunu yapabildi, çünkü kurduğu şey kendi elindeydi: bellekteki bir nesne. Düzeneğin kurduğu şey bir ağ üzerindeki paket deposu, bir saat ya da bir dosya sistemi olsaydı, “yeniden kurmak” bir seçenek olmazdı. Sonraki ders testin dışarıya uzanan bu ayağına bakar: aynı test dış kaynağın üç ayrı kipinde kaç ayrı sonuç verir, ve dış kaynağın yerine konan sahte nesne bu sayıyı neye indirir — indirdiği sonucun doğru olduğunu neye dayanarak söyleriz?

İlerlemeni kaydetmek ve not almak için Giriş yap

Notlarım

Not almak için giriş yapmalısın.

Aramak için yazmaya başlayın.

↑↓ Esc gezin · aç · kapat