Grafik yapıları kullanarak kodu nasıl test edersiniz?


18

Bir bağımlılık grafiği geziniyor bağımlılık döngüleri veya çelişkiler arar (özyinelemeli) kod yazıyorum. Ancak, bunu test eden birime nasıl yaklaşacağımdan emin değilim. Sorun, ana endişelerimizden birinin, kodun ortaya çıkabilecek tüm ilginç grafik yapıları üzerinde işlemesi ve tüm düğümlerin uygun şekilde ele alınmasını sağlamasıdır.

Bazı kodların çalıştığından emin olmak için genellikle% 100 hat veya şube kapsama alanı yeterli olsa da,% 100 yol kapsama alanı ile bile hala şüpheleriniz var gibi hissettirir.

Peki, kodlarının gerçek dünya verilerinde bulabileceğiniz tüm akla yatkın permütasyonları işleyebileceğine güvenmek için test senaryoları için grafik yapıları seçmek nasıl yapılır.


Not: Önemli olursa, grafiğimdeki tüm kenarlar "xor" olamaz "etiketli ve önemsiz döngü yok ve iki düğüm arasında yalnızca bir kenar var.


PPS- Bu ek sorun açıklaması aslen sorunun yazarı tarafından aşağıdaki yorumda yayınlanmıştır:

For all vertices N in forest F, for all vertices M, in F, such that if there are any walks between N and M they all must either use only edges labelled 'conflict' or 'requires'.


13
Herhangi bir yöntemi test ettiğiniz gibi. Her yöntem için tüm "ilginç" test senaryolarını tanımlar ve bunlar için birim testleri yazarsınız. Sizin durumunuzda, "ilginç" grafik yapıların her biri için hazır bağımlılık grafikleri oluşturmanız gerekir.
Smaç

@Dunk Bütün zor olanları ele aldığımızı düşünüyoruz ve sonra belirli bir yapının daha önce düşünmediğimiz sorunlara neden olduğunu anlıyoruz. Düşünebildiğimiz her zorluğu test etmek yaptığımız şeydir, bulmayı umduğum şey, belki de temel formların indirgenebilirliğini kullanarak zahmetli örnekler üretmek için bazı yönergeler / prosedürler .
Sled

6
Herhangi bir test formundaki sorun budur. Tek bildiğiniz iş üzerinde düşündüğünüz testler. Bu, testlerinizin geçmesi nedeniyle sw'nizin hatasız olduğu anlamına gelmez. Her projenin aynı sorunu var. Üretime başlayabilmemiz için mevcut projemi teslim etmenin son aşamalarındayım. Şimdi karşılaştığımız hata türleri oldukça belirsiz olma eğilimindedir. Örneğin, donanımın hala spesifikasyona kadar çalıştığı ancak zar zor ve aynı donanımla diğer donanımlarla eşzamanlı olarak birleştirildiği zaman problemler ortaya çıkar; ama sadece bazen :( SW iyi test edildi ama biz her şeyi düşünmedik
Dunk

Açıkladığınız şey, birim testi gibi değil, entegrasyon testi gibidir. Birim testleri, bir yöntemin grafikteki daireleri bulabilmesini sağlar. Diğer birim testleri, belirli bir grafiğin belirli bir çemberinin test edilen sınıf tarafından ele alınmasını sağlayacaktır.
SpaceTrucker

Döngü tespiti iyi kapsanan bir konudur (bkz. Knuth ve ayrıca aşağıdaki bazı cevaplar) ve çözümler çok sayıda özel durum içermez, bu yüzden önce sorununuzu böyle yapan şeyleri belirlemelisiniz. Bahsettiğiniz çelişkilerden mi kaynaklanıyor? Öyleyse, onlar hakkında daha fazla bilgiye ihtiyacımız var. Bu, uygulama tercihlerinin bir sonucuysa, belki de büyük bir şekilde yeniden düzenleme yapmanız gerekebilir. Temel olarak, bu, yolunuzu düşünmeniz gereken bir tasarım problemidir, TDD, çıkmazdan önce sizi labirentin derinliklerine götürebilecek yanlış bir yaklaşımdır.
sdenham

Yanıtlar:


5

Tüm zor olanları kapsadığımızı düşünüyoruz ve sonra belirli bir yapının daha önce düşünmediğimiz sorunlara neden olduğunu fark ediyoruz. Aklımızda tutabileceğimiz her türlü zorluğu test etmek yaptığımız şeydir.

Kulağa iyi bir başlangıç ​​gibi geliyor. Kapsam tabanlı testten daha önce bahsettiğiniz gibi, sınır değer analizi veya denklik bölümleme gibi bazı klasik teknikleri uygulamaya çalıştınız . İyi test senaryoları oluşturmak için çok zaman harcadıktan sonra, sizin, ekibinizin ve testçilerinizin (eğer varsa) fikirlerinizin bittiği bir noktaya geleceksiniz. Bu, birim test yolundan ayrılmanız ve mümkün olduğunca gerçek dünya verileriyle test yapmaya başlamanız gereken nokta .

Üretim verilerinizden çok çeşitli grafikler seçmeye çalışmanız gerektiği açıktır. Belki de sadece sürecin bu kısmı için bazı ek araçlar veya programlar yazmalısınız. Buradaki zor kısım muhtemelen program çıktılarınızın doğruluğunu doğrulamaktır, programınıza on bin farklı gerçek dünya grafiği koyduğunuzda, programınızın her zaman doğru çıktıyı üretip üretmediğini nasıl bileceksiniz? Açıkçası manuel olarak kontrol edemezsiniz. Şanslıysanız, performans beklentilerinizi karşılamayabilecek, ancak doğrulanması orijinal algoritmanızdan daha kolay olan bağımlılık kontrolünüzün ikinci, çok basit bir uygulamasını yapabilirsiniz. Ayrıca, çok sayıda olasılık kontrolünü doğrudan programınıza entegre etmeye çalışmalısınız (örneğin,

Son olarak, her testin sadece hataların varlığını kanıtlayabileceğini, ancak hataların olmadığını kanıtlamayı kabul etmeyi öğrenin.


5

1. Rasgele test üretimi

Grafik üreten bir algoritma yazın, birkaç yüz (veya daha fazla) rasgele grafik üretmesini sağlayın ve her birini algoritmanıza atın.

İlginç arızalara neden olan grafiklerin rastgele tohumlarını saklayın ve bunları birim testleri olarak ekleyin.

2. Sabit kod zor parçalar

Bildiğiniz bazı grafik yapıları hemen kodlayabilir veya bunları birleştirip algoritmanıza iten bir kod yazabilirsiniz.

3. Ayrıntılı liste oluşturun

Ancak, "kodun gerçek dünya verilerinde bulabileceğiniz akla gelebilecek tüm permütasyonları işleyebileceğinden" emin olmak istiyorsanız, bu verileri rastgele tohumdan değil, tüm permütasyonlardan geçerek oluşturmanız gerekir. (Bu, metro rayı sinyal sistemlerini test ederken yapılır ve test etmek için çok fazla zaman alan büyük miktarlarda vaka verir. Metro metroları için sistem sınırlıdır, bu nedenle permütasyon sayısının üst sınırı vardır. ) uygular


Soru soran, tüm vakaları dikkate alıp almadığını söyleyemediklerini yazmıştır, bu da onları numaralandırmanın bir yolu olmadığı anlamına gelir. Sorun alanını, bunu yapacak kadar iyi anlayana kadar, nasıl test edileceği tartışmalı bir sorudur.
sdenham

@sdenham Literatürde sonsuz sayıda olası geçerli kombinasyon içeren bir şeyi nasıl numaralandıracaksınız? "Bunlar, uygulamanızda sık sık hataları yakalayacak en zorlu grafik yapıları" satırında bir şeyler bulmayı umuyordum. Etki alanını basit olduğu için yeterince iyi anlıyorum: For all vertices N in forest F, for all vertices M, in F, such that if there are any walks between N and M they all must either use only edges labelled 'conflict' or 'requires'.Etki alanı sorun değil.
Kızak

@ArtB: Sorunu açıkladığınız için teşekkür ederiz. Söylediğiniz gibi, herhangi iki köşe arasında birden fazla kenar yoktur ve görünüşe göre döngüleri olan yolları dışlamaktadır (veya herhangi bir döngü etrafında en az bir geçiş), o zaman en azından kelimenin tam anlamıyla sonsuz sayıda ilerleme olan olası geçerli kombinasyonlar. Tüm olasılıkları nasıl numaralandıracağınızı bilmek, bunu yapmanız gerektiğini söylemekle aynı değildir, çünkü doğruluk için bir argüman yapmak için bir başlangıç ​​noktası olabilir ve bu da teste rehberlik edebilir. Ben daha fazla düşünce vereceğim ...
sdenham

@ArtB: Güncellemeyi, burada verdiğiniz sorun bildirimine ekleyecek şekilde değiştirmeniz gerekir. Ayrıca, bunların yönlendirilmiş kenarlar olduğunu (bu durumda) ve bir döngünün sadece algoritmanın işlemesi gereken bir durumdan ziyade grafikte bir hata olarak kabul edilip edilmeyeceğini belirtmeye yardımcı olabilir.
sdenham

4

Bu durumda hiçbir test yeterli olmayacak, hatta tonlarca gerçek dünya verisi veya tüylenme bile olmayacak. % 100 kod kapsamı, hatta% 100 yol kapsamı, özyinelemeli işlevleri sınamak için yetersizdir.

Özyinelemeli işlev resmi bir kanıta dayanır (bu durumda o kadar zor olmamalıdır) veya değildir. Kod, yan etkileri dışlamak için uygulamaya özgü kodla çok fazla iç içe geçmişse, buradan başlayabilirsiniz.

Algoritmanın kendisi, basit bir geniş ilk aramaya benzer, tüm düğümlerden çalıştırılan ziyaret edilen düğümlerin listesiyle kesişmemesi gereken bir kara listenin eklenmesiyle basit bir sel algoritması gibi geliyor.

foreach nodes as node
    foreach nodes as tmp
        tmp.status = unmarked

    tovisit = []
    tovisit.push(node)
    node.status = required

    while |tovisit| > 0 do
        next = tovisit.pop()
        foreach next.requires as requirement
            if requirement.status = unmarked
                tovisit.push(requirement)
                requirement.status = required
            else if requirement.status = blacklisted
                return false
        foreach next.collides as collision
            if collision.status = unmarked
                requirement.status = blacklisted
            else if requirement.status = required
                return false
return true

Bu yinelemeli algoritma, başlangıç ​​yapısının her zaman gerekli olduğu herhangi bir rastgele yapay nesneden başlayarak, keyfi yapının grafikleri için hiçbir bağımlılığın gerekmemesi ve kara listeye alınmaması koşulunu yerine getirir.

Kendi uygulamanız kadar hızlı olsa da olmasa da, tüm durumlar için sona erdiği kanıtlanabilir (dış döngünün her yinelemesinde olduğu gibi, her bir eleman tovisitkuyruğa sadece bir kez itilebilir ), tüm ulaşılabiliri doldurur grafik (endüktif kanıt) içerir ve her düğümden başlayarak bir artefaktın aynı anda kara listeye alınması gereken tüm durumları algılar.

Kendi uygulamanızın aynı özelliklere sahip olduğunu gösterebiliyorsanız, birim testine neden olmadan doğruluğu kanıtlayabilirsiniz. Sadece kuyrukları itme ve atma, kuyruk uzunluğunu sayma, özellikler üzerinde yineleme ve benzerleri için temel yöntemlerin test edilmesi ve yan etkilerden arındırılmış olması gerekir.

DÜZENLEME: Bu algoritmanın kanıtlamadığı şey, grafiğinizde döngü olmaması. Yönlendirilmiş asiklik grafikler iyi araştırılmış bir konudur, bu nedenle bu özelliği kanıtlamak için hazır bir algoritma bulmak da kolay olmalıdır.

Gördüğünüz gibi, tekerleği yeniden icat etmeye gerek yok.


3

"Tüm ilginç grafik yapıları" ve "uygun şekilde işlenmiş" gibi ifadeler kullanıyorsunuz. Kodunuzu tüm bu yapılara karşı test etmenin ve kodun grafiği uygun şekilde işleyip işlemediğini belirlemenin yolları yoksa, yalnızca test kapsamı analizi gibi araçları kullanabilirsiniz.

Bir dizi ilginç grafik yapısı ile bulup test ederek başlamanızı ve uygun işlemin ne olacağını belirlemenizi ve kodun bunu yaptığını görmenizi öneririm. Daha sonra, bu grafikleri bir) kuralları ihlal eden kırık grafikler veya b) sorunları olan ilginç olmayan grafikler; kodunuzun doğru şekilde işlenemediğine bakın.


Bu test için iyi bir yaklaşım olsa da, sorunun temel sorununu çözmez: tüm vakaların ele alınmasını nasıl sağlar? Bunun daha fazla analiz ve muhtemelen yeniden düzenleme gerektireceğine inanıyorum - yukarıdaki soruma bakın.
sdenham


2

Test etmek bu tür bir algoritma söz konusu olduğunda, algoritmayı testlere dayalı olarak oluşturduğunuz TDD için gideceğim,

Kısaca TDD,

  • testi yaz
  • bakın başarısız oluyor
  • kodu değiştir
  • tüm testlerin geçtiğinden emin ol
  • refactor

ve döngüyü tekrarlayın,

Bu özel durumda,

  1. İlk test, algoritmanın herhangi bir döngü döndürmemesi gereken tek düğümlü grafik olurdu
  2. İkincisi, algoritmanın herhangi bir döngü döndürmemesi gereken döngü olmayan üç düğüm grafiği olacaktır
  3. Bir sonraki adım, algoritmanın herhangi bir döngü döndürmemesi gereken bir döngü ile üç düğüm grafiği kullanmak olacaktır
  4. Şimdi olasılıklara bağlı olarak biraz daha karmaşık bir döngüye karşı test edebilirsiniz

Bu yöntemin önemli bir yönü, her zaman olası adım için bir test eklemeniz gerektiğidir (olası senaryoları basit testlere böldüğünüzde) ve olası tüm senaryoları kapsadığınızda algoritma genellikle otomatik olarak gelişir.

Son olarak, öngörülemeyen herhangi bir sorun olup olmadığını görmek için bir veya daha fazla karmaşık Entegrasyon testi eklemeniz gerekir (grafiğiniz çok büyük olduğunda ve özyineleme kullandığınızda yığın taşması hataları / performans hataları gibi)


2

Orijinal olarak ifade edilen ve daha sonra Macke'nin cevabı altındaki yorumlarla güncellenen problem hakkındaki anlayışım şunları içerir: 1) her iki kenar tipi (bağımlılıklar ve çatışmalar) yönlendirilir; 2) iki düğüm bir kenarla bağlanırsa, diğer türden veya ters olsa bile, başka bir düğümle bağlanmamalıdır; 3) farklı tipteki kenarların karıştırılmasıyla iki düğüm arasındaki bir yol oluşturulabilirse, bu göz ardı edilen bir durumdan ziyade bir hatadır; 4) Bir türün kenarlarını kullanan iki düğüm arasında bir yol varsa, diğer türün kenarlarını kullanan aralarında başka bir yol olmayabilir; 5) tek kenarlı tip veya karışık kenar tipli döngülere izin verilmez (uygulamadaki bir tahminden, sadece çakışma döngülerinin bir hata olduğundan emin değilim, ancak bu koşul kaldırılabilir, değilse).

Ayrıca, kullanılan veri yapısının, bu gereksinimlerin ihlallerinin ifade edilmesini engellemediğini varsayacağım (örneğin, bir grafik ihlali koşulu 2, düğüm çifti her zaman düğüm çiftinden (tip, yön) bir haritada ifade edilemedi önce en az numaralı düğüme sahiptir.) Belirli hatalar ifade edilemezse, dikkate alınacak vaka sayısını azaltır.

Aslında burada dikkate alınabilecek üç grafik vardır: sadece bir kenar tipinden ikisi ve iki tipten her birinin birleşmesiyle oluşan karışık grafik. Bunu, belirli sayıda düğüme kadar tüm grafikleri sistematik olarak oluşturmak için kullanabilirsiniz. Öncelikle, sıralı iki düğüm çifti arasında birden fazla kenarı olmayan N düğümlerinin tüm olası grafiklerini oluşturun (bunlar yönlendirilmiş grafikler olduğu için sıralı çiftler.) Şimdi, bu grafiklerin biri bağımlılıkları ve diğeri çakışmaları temsil eden tüm olası çiftlerini alın ve her bir çiftin birliğini oluşturur.

Veri yapınız koşul 2 ihlallerini ifade edemezse, yalnızca bağımlılık grafiklerinin boşluklarına uyan olası tüm çatışma grafiklerini oluşturarak dikkate alınacak vakaları önemli ölçüde azaltabilirsiniz veya bunun tersi de geçerlidir. Aksi takdirde, birleşmeyi oluştururken durum 2 ihlallerini tespit edebilirsiniz.

İlk düğümden birleştirilmiş grafiğin eninde bir ilk geçişinde, her erişilebilir düğüme giden tüm yol kümesini oluşturabilirsiniz ve bunu yaptığınızda, tüm koşulların ihlallerini kontrol edebilirsiniz (döngü tespiti için, Tarjan'ın algoritmasını kullanın .)

Başka bir düğümden gelen yollar, başka bir durumda ilk düğümden gelen yollar olarak görüneceğinden, grafik bağlantısı kesilmiş olsa bile yalnızca ilk düğümün yollarını dikkate almanız gerekir.

Karışık kenarlı yollar hata olmaktan ziyade basitçe göz ardı edilebilirse (koşul 3), bağımlılık ve çakışma grafiklerini bağımsız olarak düşünmek ve bir düğümde bir düğümün ulaşılabilir olup olmadığını kontrol etmek yeterlidir.

N-1 düğümlerinin grafiklerini incelerken bulunan yolları hatırlarsanız, bunları N düğümlerinin grafiklerini oluşturmak ve değerlendirmek için başlangıç ​​noktası olarak kullanabilirsiniz.

Bu, düğümler arasında aynı türde birden çok kenar oluşturmaz, ancak bunu yapmak için genişletilebilir. Bununla birlikte, bu durum vaka sayısını büyük ölçüde artıracaktır, bu nedenle test edilen kodun bunu temsil etmeyi imkansız hale getirmesi veya başarısız olması daha önce tüm bu vakaları filtrelemesi daha iyi olurdu.

Böyle bir kehanet yazmanın anahtarı, verimsiz olmak anlamına gelse bile mümkün olduğunca basit tutmaktır, böylece ona güvenebilirsiniz (ideal olarak, doğruluğu için argümanlar yoluyla, testle desteklenir).

Test senaryoları oluşturmak için araçlara sahip olduğunuzda ve iyiyi kötülükten doğru bir şekilde ayırmak için oluşturduğunuz kehanete güvendiğinizde, bunu hedef kodun otomatik testini yürütmek için kullanabilirsiniz. Bu mümkün değilse, bir sonraki en iyi seçeneğiniz, farklı durumlar için sonuçları taramaktır. Oracle bulduğu hataları sınıflandırabilir ve her bir türün yollarının sayısı ve uzunluğu ve her iki yol türünün başlangıcında düğüm olup olmadığı gibi kabul edilen durumlar hakkında size bilgi verebilir. daha önce görmediğiniz vakaları aramanıza yardımcı olabilir.

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.