Üstel test vakalarının gerekli olduğu durumlarda TDD ve eksiksiz test kapsamı


18

Müşterimizden gelen çok özel gereksinimlere göre arama sonuçlarının sırasız bir listesini sıralamaya yardımcı olmak için bir liste karşılaştırıcısı üzerinde çalışıyorum. Gereklilikler, önem sırasına göre aşağıdaki kurallara göre sıralanmış bir alaka düzeyi algoritması gerektirir:

  1. Adla tam eşleşme
  2. Arama sorgusu adındaki tüm kelimeler veya sonucun eş anlamlısı
  3. Arama sorgusunun adı veya sonucun eş anlamlısı olan bazı kelimeleri (% azalan)
  4. Açıklamasında arama sorgusunun tüm kelimeleri
  5. Açıklamasında arama sorgusundan bazı kelimeler (% azalan)
  6. Son değiştirilme tarihi azalan

Bu karşılaştırıcı için doğal tasarım seçimi, 2 gücüne dayanan puanlı bir sıralama gibi görünüyordu. Daha az önemli kuralların toplamı, yüksek önem kuralındaki hiçbir zaman pozitif bir eşleşmeden daha fazla olamaz. Bu, aşağıdaki puanla elde edilir:

  1. 32
  2. 16
  3. 8 (% inişe göre ikincil tie-breaker puanı)
  4. 4
  5. 2 (% inişe göre ikincil tie-breaker puanı)
  6. 1

TDD ruhunda önce birim testlerimle başlamaya karar verdim. Her bir benzersiz senaryo için bir test senaryosuna sahip olmak, kural 3 ve 5'teki ikincil kravat kırıcı mantığı için ek test senaryolarını dikkate almayan en az 63 benzersiz test vakasında olacaktır.

Gerçek testler aslında daha az olacaktır. Gerçek kurallara bağlı olarak, bazı kurallar daha düşük kuralların her zaman doğru olmasını sağlar (Örn. 'Tüm Arama Sorgusu sözcükleri açıklamada göründüğünde' kuralı 'Kural' Bazı Arama Sorgusu kelimeleri açıklamada görünür 'her zaman doğrudur). Bu test senaryolarının her birini yazma çabası hala buna değer mi? Bu, TDD'de% 100 test kapsamı hakkında konuşurken genellikle çağrılan test seviyesi midir? Değilse, kabul edilebilir bir alternatif test stratejisi ne olurdu?


1
Bu senaryo ve benzerleri, test kodunu bir kez yazabileceğiniz ve girişleri ve beklenen sonucu içeren iki veya daha fazla diziyi besleyebileceğiniz bir "TMatrixTestCase" ve numaralandırıcı geliştirmemizin nedenidir.
Marjan Venema

Yanıtlar:


17

Sorunuz TDD'nin "önce tüm test senaryolarını yazmak" ile ilgisi olduğunu gösteriyor. IMHO "TDD'nin ruhunda" değil, aslında buna karşı . TDD'nin "test odaklı geliştirme" anlamına geldiğini unutmayın , bu nedenle yalnızca uygulamanızı gerçekten " yönlendiren " test senaryolarına ihtiyacınız vardır, daha fazla değil. Ayrıca, uygulamanız her yeni gereksinimle birlikte kod bloklarının sayısının katlanarak arttığı bir şekilde tasarlanmadığı sürece, üstel sayıda test vakasına da ihtiyacınız olmayacaktır. Örneğinizde, TDD döngüsü muhtemelen şöyle görünecektir:

  • listenizdeki ilk gereksinimle başlayın: "Adında tam eşleşme" bulunan kelimeler diğer her şeyden daha yüksek bir puan almalıdır
  • şimdi bunun için bir ilk test senaryosu yazıyorsunuz (örneğin: belirli bir sorguyla eşleşen bir kelime) ve bu test geçişini sağlayan minimum çalışma kodu miktarını uyguluyorsunuz
  • birinci gereksinim için ikinci bir test senaryosu ekleyin (örneğin: sorguyla eşleşmeyen bir kelime) ve yeni bir test vakası eklemeden önce 2. test geçene kadar mevcut kodunuzu değiştirin
  • Uygulamanızın ayrıntılarına bağlı olarak, boş bir sorgu, boş bir kelime vb.Gibi daha fazla test örneği eklemekten çekinmeyin (unutmayın: TDD beyaz kutu yaklaşımıdır, uygulamanızı bildiğiniz gerçeğinden yararlanabilirsiniz. Test durumlarınızı tasarlayın).

Ardından, 2. gereksinimle başlayın:

  • "Arama sorgusu adındaki tüm kelimeler veya sonucun eşanlamlısı", "Adda tam eşleme" den daha düşük bir puan almalı, ancak diğer her şeyden daha yüksek bir puan almalıdır.
  • şimdi bu yeni gereksinim için, tıpkı yukarıdaki gibi, birbiri ardına test senaryoları oluşturun ve her yeni testten sonra kodunuzun bir sonraki bölümünü uygulayın. Kodunuzun yanı sıra test durumlarınız arasında yeniden düzenleme yapmayı unutmayın.

İşte yakalama : gereksinim / kategori numarası "n" için test senaryoları eklediğinizde, sadece "n-1" kategorisinin puanının "n" kategorisi puanından daha yüksek olduğundan emin olmak için testler eklemeniz gerekir. . Daha önce yazdığınız testler, bu kategorilerin puanlarının hala doğru sırada olduğundan emin olacağından, 1, ..., n-1 kategorilerinin diğer tüm kombinasyonları için test senaryosu eklemenize gerek yoktur.

Bu, size, katlanarak değil, ihtiyaç sayısı ile yaklaşık olarak doğrusal olarak büyüyen bir dizi test örneği verecektir.


1
Bu cevabı gerçekten çok beğendim. TDD'yi akılda tutarak bu soruna yaklaşmak için açık ve özlü bir birim test stratejisi sağlar. Oldukça güzel bir şekilde bozuyorsun.
maple_shaft

@ maple_shaft: teşekkürler ve sorunuzu gerçekten beğendim. Öncelikle tüm test senaryolarını tasarlama yaklaşımınızla bile, testler için klasik denklik sınıfları oluşturma tekniğinin üstel büyümeyi azaltmak için yeterli olabileceğini tahmin etmeyi seviyorum (ama şimdiye kadar çalışmadım).
Doc Brown

13

Önceden tanımlanmış bir koşullar listesinden geçen ve her başarılı kontrol için geçerli puanı 2 ile çarparak bir sınıf yazmayı düşünün.

Bu, sadece birkaç sahte test kullanılarak çok kolay bir şekilde test edilebilir.

Daha sonra her koşul için bir sınıf yazabilirsiniz ve her durum için sadece 2 test vardır.

Kullanım durumunuzu gerçekten anlamıyorum, ancak umarım bu örnek size yardımcı olacaktır.

public class ScoreBuilder
{
    private ISingleScorableCondition[] _conditions;
    public ScoreBuilder (ISingleScorableCondition[] conditions)
    {
        _conditions = conditions;
    }

    public int GetScore(string toBeScored)
    {
        foreach (var condition in _conditions)
        {
            if (_conditions.Test(toBeScored))
            {
                // score this somehow
            }
        }
    }
}

public class ExactMatchOnNameCondition : ISingleScorableCondition
{
    private IDataSource _dataSource;
    public ExactMatchOnNameCondition(IDataSource dataSource)
    {
        _dataSource = dataSource;
    }

    public bool Test(string toBeTested)
    {
        return _dataSource.Contains(toBeTested);
    }
}

// etc

2 ^ koşul testinizin hızlı bir şekilde 4+ (2 * koşul) seviyesine düştüğünü göreceksiniz. 20, 64'ten çok daha az zorlayıcıdır. Ve daha sonra başka bir tane eklerseniz, mevcut sınıflardan HERHANGİ BİRİNİ değiştirmek zorunda kalmazsınız (açık-kapalı prensibi), bu yüzden 64 yeni test yazmak zorunda değilsiniz, sadece 2 yeni testle başka bir sınıf eklemek ve bunu ScoreBuilder sınıfınıza enjekte etmek.


İlginç bir yaklaşım. Tüm zaman boyunca aklım tek bir karşılaştırıcı bileşenin aklımda kaldığından OOP yaklaşımını hiç düşünmedi. Gerçekten algoritma tavsiyesi aramıyordum ama bu ne olursa olsun çok yararlı.
maple_shaft

4
@maple_shaft: Hayır, ancak TDD tavsiyesi arıyordunuz ve bu tür algoritmalar, çabayı büyük ölçüde azaltarak, çabaya değip değmeyeceği sorusunu kaldırmak için mükemmel. Karmaşıklığı azaltmak TDD'nin anahtarıdır.
pdr

+1, harika cevap. Böyle sofistike bir çözüm olmasa bile, test senaryolarının sayısının katlanarak artması gerekmediğine inanıyorum (aşağıdaki cevabıma bakın).
Doc Brown

Cevabınızı kabul etmedim çünkü başka bir cevabın gerçek soruyu daha iyi ele aldığını hissettim, ancak tasarım yaklaşımınızı o kadar çok sevdim ki önerdiğiniz şekilde uyguluyorum. Bu karmaşıklığı azaltır ve uzun vadede daha genişletilebilir hale getirir.
maple_shaft

4

Bu test senaryolarının her birini yazma çabası hala buna değer mi?

"Buna değer" tanımlamanız gerekir. Bu tür bir senaryo ile ilgili sorun, testlerin kullanışlılığının azalmasıdır. Yazdığınız ilk test kesinlikle buna değecektir. Öncelikte belirgin hatalar ve hatta kelimeleri parçalamaya çalışırken hataları ayrıştırma gibi şeyler bulabilir.

İkinci test buna değer olacaktır, çünkü muhtemelen başka bir öncelik ilişkisini kontrol ederek kod boyunca farklı bir yolu kapsar.

63. test muhtemelen buna değmez, çünkü% 99.99'dan emin olduğunuz bir şey, kodunuzun mantığı veya başka bir test tarafından kapsanır.

Bu, TDD'de% 100 test kapsamı hakkında konuşurken genellikle çağrılan test seviyesi midir?

Anladığım kadarıyla% 100 kapsam, tüm kod yollarının kullanıldığı anlamına gelir. Bu, kurallarınızın tüm kombinasyonlarını yaptığınız anlamına gelmez, ancak kodunuzun aşağıya inebileceği tüm farklı yollar (işaret ettiğinizde, kodda bazı kombinasyonlar bulunamaz). Ancak TDD yaptığınızdan, henüz yolları kontrol etmek için bir "kod" yoktur. Sürecin mektubu 63+ yapmak anlamına gelir.

Şahsen,% 100 kapsama alanı bir boru rüyası olarak görüyorum. Bunun ötesinde, bu çok pratik değil. Ünite testleri size hizmet etmek için mevcuttur, tam tersi değildir. Daha fazla test yaptığınızda, faydadan azalan getiri elde edersiniz (testin bir hatayı önleme olasılığı + kodun doğru olduğuna dair güven). Kodunuzun ne yaptığına bağlı olarak, bu kayan ölçekte nerede test yapmayı bıraktığınızı tanımlar. Kodunuz bir nükleer reaktör çalıştırıyorsa, belki de 63+ testin hepsi buna değer. Kodunuz müzik arşivinizi düzenliyorsa, muhtemelen çok daha azıyla kurtulabilirsiniz.


"kapsama alanı" tipik olarak kod kapsamı (her kod satırı yürütülür) veya şube kapsamı (her şube mümkün olan en az bir kez yürütülür) anlamına gelir. Her iki kapsama türü için 64 farklı test senaryosuna gerek yoktur. En azından, 64 vakanın her biri için ayrı kod parçaları içermeyen ciddi bir uygulama ile değil. Böylece% 100 kapsama alanı tamamen mümkündür.
Doc Brown

@DocBrown - emin, bu durumda - diğer şeyleri test etmek zor / imkansızdır; bellek dışı özel durum yollarını göz önünde bulundurun. TDD'nin 64 harfinde 'mektubu ile' davranışın uygulanması için uygulamadan habersiz olunması gerekmez mi?
Telastyn

Yorumum soru ile ilgiliydi ve cevabınız OP durumunda % 100 kapsama alınmasının zor olabileceği izlenimini veriyor . Bundan şüpheliyim. Ve% 100 kapsama alanının elde edilmesinin daha zor olduğu durumlar oluşturabileceğine katılıyorum, ancak bu istenmedi.
Doc Brown

4

Bunun TDD için mükemmel bir durum olduğunu iddia ediyorum .

Bu vakaların mantıklı bir dökümü ile test etmek için bilinen bir dizi ölçütünüz var. Bunları şimdi veya daha sonra test edeceğinizi varsayarsak, bilinen sonucu alıp etrafında inşa etmek mantıklı görünüyor, aslında her bir kuralı bağımsız olarak ele aldığınızdan emin olun.

Ayrıca, yeni bir arama kuralı eklediğinizde var olan bir kuralı bozarsa, gittiğinizi öğrenirsiniz. Tüm bunları kodlamanın sonunda yaparsanız, muhtemelen birini düzeltmek için bir başkasını bozan, diğerini kıran, diğerini kıran daha büyük bir risk taşırsınız ... Ve, tasarımlarınızı geçerli olup olmadığını kuralları uygularken veya ayar gerekiyor.


1

% 100 test kapsamını her yönteme karşı teknik özellik olarak yorumlama veya kodun her permütasyonunu test etme hayranı değilim. Bunu fanatik bir şekilde yapmak, iş mantığınızı doğru şekilde kapsamayan ve genellikle desteklenen iş mantığını tanımlamak açısından anlamsız olan testler / spesifikasyonlar sağlayan sınıflarınızın test odaklı bir tasarımına yol açar. Bunun yerine, testleri iş kurallarının kendileri gibi yapılandırmaya odaklanıyorum ve testlerin test cihazının genel kullanım durumları olarak kolayca anlaşılabileceği ve aslında açıkladığı gibi açık bir beklenti ile kodun her koşullu dalını testlerle kullanmaya çalışıyorum. uygulanan işletme kuralları.

Bu fikir göz önünde bulundurularak, sonuçlarınızı beklenen genel sıralama değerlerine yuvarlamanızı sağlayan 2 veya 3 entegrasyon stili testi ile takip ettiğiniz 6 sıralama faktörünü birbirinden ayrı olarak kapsamlı bir şekilde birim test ederdim. Örneğin, durum # 1, İsimle Tam Eşleşme, tam ve ne zaman değil ve iki senaryo beklenen puanı döndürdüğünü test etmek için en az iki birim testim olurdu. Büyük / küçük harfe duyarlıysa, "Tam Eşleme" ile "tam eşleme" ve muhtemelen noktalama işaretleri, ekstra boşluklar vb. Gibi diğer giriş varyasyonlarını test etmek için de bir durum beklenir.

Sıralama puanlarına katkıda bulunan tüm bireysel faktörler üzerinde çalıştıktan sonra, bunların entegrasyon seviyesinde doğru bir şekilde çalıştığını varsayıyorum ve birleşik faktörlerinin beklenen son sıralama puanına doğru katkıda bulunmasına odaklanıyorum.

# 2 / # 3 ve # 4 / # 5 vakalarının aynı temel yöntemlerle genelleştirildiğini varsayarsak, ancak farklı alanları geçirirken, temeldeki yöntemler için sadece bir birim test seti yazmanız ve belirli testleri test etmek için basit ek birim testleri yazmanız gerekir. alanları (başlık, isim, açıklama vb.) ve belirlenen faktoringde puanlama sayesinde genel test çalışmalarınızın fazlalığını azaltır.

Bu yaklaşımla, yukarıda tarif edilen yaklaşım muhtemelen vaka 1 üzerinde 3 veya 4 birim test, belki de bazı / tüm eş anlamlılar için 10 özellik - artı vakaların 2 - # 5 ve 2 doğru skorlaması için 4 özellik verecektir. sipariş edilen son tarih sıralamasında 3 spesifikasyona, ardından 6 vakanın tümünü olası yollarla bir araya getiren 3 ila 4 entegrasyon seviyesi testi (kodunuzda sağlanması gereken bir sorunu açıkça görmediğiniz sürece şimdilik kesin kenarları unutun bu koşul ele alınır) veya daha sonraki revizyonlar tarafından ihlal edilmediğinden / bozulmadığından emin olun . Bu, yazılan kodun% 100'ünü kullanmak için yaklaşık 25 veya daha fazla özellik verir (yazılan yöntemlerin% 100'ünü doğrudan çağırmasanız bile).


1

Hiç% 100 test kapsamı hayranı olmadım. Deneyimlerime göre, bir şey sadece bir veya iki test vakasıyla test edilecek kadar basitse, nadiren başarısız olacak kadar basittir. Başarısız olduğunda, genellikle yine de test değişiklikleri gerektiren mimari değişiklikler nedeniyle.

Bununla birlikte, sizinki gibi gereksinimler için, kimsenin beni yapmadığı kişisel projelerde bile her zaman kapsamlı bir şekilde test yapıyorum, çünkü birim testinin size zaman ve ağırlaşma kazandırdığı durumlar bunlar. Bir şeyi test etmek için ne kadar çok birim testi gerekiyorsa, birim testleri o kadar fazla zaman kazandırır.

Çünkü bir kerede kafanızda çok fazla şey tutabilirsiniz. 63 farklı kombinasyon için çalışan kod yazmaya çalışıyorsanız, bir kombinasyonu diğerini kırmadan düzeltmek genellikle zordur. Sonunda diğer kombinasyonları manuel olarak test edersiniz. Manuel test çok daha yavaştır, bu da her değişiklik yaptığınızda olası her kombinasyonu yeniden çalıştırmak istememenizi sağlar. Bu, bir şeyi kaçırma olasılığınızı artırır ve tüm durumlar için çalışmayan yolları takip ederek zaman kaybetme olasılığınızı artırır.

Manuel testlere kıyasla tasarruf edilen zamanın yanı sıra, daha az zihinsel zorlanma vardır, bu da yanlışlıkla regresyonlara girme endişesi olmadan eldeki probleme odaklanmayı kolaylaştırır. Bu, tükenmişlik olmadan daha hızlı ve daha uzun süre çalışmanıza olanak tanır. Benim düşünceme göre, zihinsel sağlık yararları, sizi hiçbir zaman kurtarmasa bile, karmaşık kodu test etme birim maliyetine değer.

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.