Doğası gereği rasgele / deterministik olmayan algoritmaların birim testi


41

Şu anki projem, kısaca, "sınırlanabilir-rastgele olayların" yaratılmasını içeriyor. Temel olarak bir teftiş programı oluşturuyorum. Bazıları katı program kısıtlamalarına dayanır; Cuma günleri saat 10: 00'da haftada bir kez inceleme yaparsınız. Diğer denetimler “rastgele”; "bir denetim haftada 3 kez yapılmalı", "muayene 9:00 - 9:00 arasında yapılmalı" ve "aynı 8 saatlik sürede iki denetim yapılmamalı" gibi temel yapılandırılabilir gereksinimler vardır, ancak Belirli bir denetleme kümesi için ne gibi kısıtlamalar yapıldıysa, ortaya çıkan tarih ve saatler öngörülebilir olmamalıdır.

Ünite testleri ve TDD, IMO, bu sistemde büyük bir değere sahiptir, çünkü tüm gereksinimler hala tamamlanmamışken, aşamalı olarak inşa etmek için kullanılabilir ve benim yaptığım işleri yapmak için "fazla mühendislik yapmadığımdan" emin olun şu anda ihtiyacım olduğunu bilmiyor. Kesin programlar TDD'ye bir parça kek oldu. Ancak, sistemin rastgele bölümü için testler yazarken ne test ettiğimi gerçekten tanımlamakta zorlanıyorum. Zamanlayıcı tarafından üretilen tüm zamanların kısıtlamalara uyması gerektiğini söyleyebilirim, ancak gerçek zamanları "rastgele" olmadan bu tür testleri geçen bir algoritma uygulayabilirim. Aslında olan tam olarak buydu; Saatlerin tam olarak tahmin edilebilir olmasa da izin verilen tarih / saat aralıklarının küçük bir alt kümesine düştüğü bir sorun buldum. Algoritma hala makul bir şekilde yapabileceğimi düşündüğüm tüm iddiaları geçti ve bu durumda başarısız olacak bir otomatik test tasarlayamadım, ancak "daha rastgele" sonuçlar verildiğinde geçtim. Sorunun, bazı testlerin kendilerine birkaç kez tekrarlanacak şekilde yeniden yapılandırılmasıyla çözüldüğünü göstermek zorunda kaldım ve görsel olarak oluşturulan zamanın tam izin verilen aralıkta olduğunu kontrol ettim.

Deterministik olmayan davranışlar beklemesi gereken testler tasarlamak için herhangi bir ipucu var mı?


Önerileriniz için herkese teşekkürler. Ana görüş , deterministik, tekrarlanabilir, iddialı sonuçlar elde etmek için deterministik bir teste ihtiyacım var gibi görünüyor . Mantıklı.

Sınırlama işlemi için aday algoritmaları içeren bir "sandbox" testi seti yarattım (herhangi bir uzunluğa sahip olabilecek bir bayt dizisinin bir dakika ile maksimum arasında uzun sürdüğü süreç). Daha sonra algoritmayı algoritma veren ve bilinen birkaç byte dizisini (sadece başlangıç ​​için 1 ila 10,000,000 arası değerler) veren ve algoritmanın her birini 1009 ile 7919 arasında bir değere sınırlayan bir FOR döngüsü üzerinden çalıştırıyorum. algoritması giriş ve çıkış aralıkları arasında bazı serpitoptous GCF tarafından geçmez). Elde edilen sınırlanmış değerler sayılır ve bir histogram üretilir. "Geçiş" için, tüm girişler histogramın içine yansıtılmalıdır (hiçbirini "kaybetmememiz için sağlığımız) ve histogramdaki herhangi iki kova arasındaki fark 2'den büyük olamaz (gerçekten <= 1 olmalıdır) , ama bizi izlemeye devam edin). Varsa, kazanan algoritma doğrudan üretim koduna kesilebilir ve yapıştırılabilir ve regresyon için kalıcı bir test uygulanabilir.

İşte kod:

    private void TestConstraintAlgorithm(int min, int max, Func<byte[], long, long, long> constraintAlgorithm)
    {
        var histogram = new int[max-min+1];
        for (int i = 1; i <= 10000000; i++)
        {
            //This is the stand-in for the PRNG; produces a known byte array
            var buffer = BitConverter.GetBytes((long)i);

            long result = constraintAlgorithm(buffer, min, max);

            histogram[result - min]++;
        }

        var minCount = -1;
        var maxCount = -1;
        var total = 0;
        for (int i = 0; i < histogram.Length; i++)
        {
            Console.WriteLine("{0}: {1}".FormatWith(i + min, histogram[i]));
            if (minCount == -1 || minCount > histogram[i])
                minCount = histogram[i];
            if (maxCount == -1 || maxCount < histogram[i])
                maxCount = histogram[i];
            total += histogram[i];
        }

        Assert.AreEqual(10000000, total);
        Assert.LessOrEqual(maxCount - minCount, 2);
    }

    [Test, Explicit("sandbox, does not test production code")]
    public void TestRandomizerDistributionMSBRejection()
    {
        TestConstraintAlgorithm(1009, 7919, ConstrainByMSBRejection);
    }

    private long ConstrainByMSBRejection(byte[] buffer, long min, long max)
    {
        //Strip the sign bit (if any) off the most significant byte, before converting to long
        buffer[buffer.Length-1] &= 0x7f;
        var orig = BitConverter.ToInt64(buffer, 0);
        var result = orig;
        //Apply a bitmask to the value, removing the MSB on each loop until it falls in the range.
        var mask = long.MaxValue;
        while (result > max - min)
        {
            mask >>= 1;
            result &= mask;
        }
        result += min;

        return result;
    }

    [Test, Explicit("sandbox, does not test production code")]
    public void TestRandomizerDistributionLSBRejection()
    {
        TestConstraintAlgorithm(1009, 7919, ConstrainByLSBRejection);
    }

    private long ConstrainByLSBRejection(byte[] buffer, long min, long max)
    {
        //Strip the sign bit (if any) off the most significant byte, before converting to long
        buffer[buffer.Length - 1] &= 0x7f;
        var orig = BitConverter.ToInt64(buffer, 0);
        var result = orig;

        //Bit-shift the number 1 place to the right until it falls within the range
        while (result > max - min)
            result >>= 1;

        result += min;
        return result;
    }

    [Test, Explicit("sandbox, does not test production code")]
    public void TestRandomizerDistributionModulus()
    {
        TestConstraintAlgorithm(1009, 7919, ConstrainByModulo);
    }

    private long ConstrainByModulo(byte[] buffer, long min, long max)
    {
        buffer[buffer.Length - 1] &= 0x7f;
        var result = BitConverter.ToInt64(buffer, 0);

        //Modulo divide the value by the range to produce a value that falls within it.
        result %= max - min + 1;

        result += min;
        return result;
    }

... ve işte sonuçlar:

görüntü tanımını buraya girin

LSB reddi (sayıyı aralık içine düşene kadar kaydırmak) KORKUNÇtu, açıklaması çok kolay. herhangi bir sayıyı maksimumdan küçük olana kadar 2'ye böldüğünüzde, sonuçları en kısa sürede bırakabilirsiniz ve önemsiz olmayan herhangi bir aralık için sonuçları üst üçe doğru sapacak (histogramın ayrıntılı sonuçlarında görüldüğü gibi) ). Bu tam olarak bitmiş tarihlerden beri gördüğüm davranıştı; her zaman öğleden sonraydı, çok özel günlerde.

MSB reddi (aralıktakie kadar her seferinde bir numaradaki en önemli bitin çıkarılması) daha iyidir, ancak yine de, çünkü her bitle çok büyük sayıları kesersiniz, eşit olarak dağıtılmaz; Sayıları üst ve alt uçlarda elde etme ihtimaliniz yoktur, bu nedenle orta üçte birine karşı bir önyargı elde edersiniz. Bu, rastgele verileri bellish eğrisine "normalleştirmek" isteyen birisinin yararına olabilir, ancak iki veya daha fazla küçük rasgele sayıların (zar atmaya benzer) toplamı size daha doğal bir eğri verecektir. Amaçlarım için başarısız.

Bu testi geçen tek kişi, üçünün de en hızlı olduğu ortaya çıkan modulo bölünmesiyle kısıtlamaktı. Modulo, tanımı gereği, mevcut girdiler göz önüne alındığında mümkün olduğu kadar eşit bir dağılım üretecektir.


2
Yani, sonuçta, rasgele bir sayı üretecinin çıktısına bakan ve rastgele olup olmadığına karar veren bir program mı istiyorsunuz? "5,4,10,31,120,390,2,3,4" olduğu gibi rastgele fakat "49,39,1,10,103,12,4,189" değildi?
psr

Hayır, ancak gerçek PRNG ile nihai sonuç arasında önyargı vermekten kaçınmak iyi olurdu.
KeithS

Sonra PRNG'yi taklit etmek tamam olur gibi geliyor. Değerleri kontrol etmediğinizi test etmek için gerçek rastgele değerlere ihtiyacınız yok. Rasgele değerleri çok küçük bir izin verilen aralıklar alt kümesine sıkıştıran bir hata varsa, belirli bazı değerleri yanlış almalısınız .
psr

Ayrıca kombinasyonları test etmelisiniz. Saatte kabaca eşit beklenen denetimlere sahip olmak, Salı günü saat 11: 00'de yapılan bir incelemenin ardından Perşembe günü saat 14: 00'de ve Cuma günü saat 10: 00'da gerçekleştiği duruma karşı koruma sağlamaz.
David Thornley

Bu, PRNG'nin kendisinin bir testidir; Yukarıda yapılandırıldığı gibi kısıtlama mekanizmalarının / mekanizmalarının testi her zaman böyle bir testten başarısız olur, çünkü buna tamamen rastgele olmayan bir veri seti verilir. Kısıtlama mekanizmasının, bir birim testinin yapmaması gereken bir şey olan "dışsalları sınama" olarak adlandırdığı rasgele verileri "sıralamaya" çaba göstermediğini farz ediyorum.
KeithS

Yanıtlar:


17

Burada gerçekten test etmek istediğinizi varsayalım, rasgele seçiciden belirli bir sonuç kümesi verildiğinde, yöntemin geri kalanının doğru şekilde çalıştığını varsayalım.

Eğer aradığınız şey buysa , test alemlerinde belirleyici olmasını sağlamak için randomizatörle alay edin.

Genel olarak, GUID jeneratörleri ve DateTime.Now da dahil olmak üzere her türlü deterministik olmayan veya öngörülemeyen (testin yazıldığı sırada) veriler için alaycı nesnelerim var.

Düzenleme, yorumlardan: PRNG (dün gece benden kaçan terim) ile mümkün olan en düşük seviyede alay etmelisin - yani. Bayt dizisi oluşturduğunda, bunları Int64'lere dönüştürdükten sonra değil. Hatta her iki seviyede de, bir Int64 çalışmasına dönüşümünüzü istediğiniz şekilde çalıştırabilir ve bir DateTimes dizisine dönüştürmenizin amaçlandığı gibi çalıştığını ayrı ayrı test edebilirsiniz. Jonathon'un dediği gibi, bunu sadece set tohum vererek yapabilir ya da geri dönmek için bayt dizisini verebilirsiniz.

İkincisini tercih ediyorum çünkü PRNG'nin çerçeve uygulaması değişerse kırılmaz. Ancak, ona tohum vermenin bir avantajı, üretimde amaçlandığı gibi çalışmayan bir durum bulursanız, kopyalayabilmeniz için, dizinin tamamının aksine, sadece bir sayı kaydetmiş olmanızdır.

Bütün bunlar, bir nedenden dolayı sözde Rastgele Sayı Üreticisi olarak adlandırıldığını hatırlamalısınız . Bu seviyede bile bazı önyargılar olabilir .


1
Hayır. Bu durumda test etmek istediğim, randomizerin kendisidir ve randomizer tarafından oluşturulan "random" değerlerinin, izin verilenler arasında eşit olmayan bir dağılıma karşı önyargılı olmadıkları halde, yine "random" iken, belirtilen kısıtlamaların içine düştüğünü iddia eder. zaman aralıkları. Belirli bir tarih / saatin belirli bir kısıtlamayı doğru bir şekilde geçtiğini veya başarısız olduğunu belirleyici bir şekilde test edebilirim ve yapabilirim, ancak karşılaştığım asıl sorun randomizer tarafından üretilen tarihlerin önyargılı olması ve bu yüzden tahmin edilebilir olmasıdır.
KeithS

Aklıma gelen tek şey, randomizerin birkaç tarih vermesini ve bir histogram yaratmasını sağlamak ve ardından değerlerin nispeten eşit şekilde dağıldığını iddia etmek. Bu, son derece ağır elle görünmektedir ve gerçek anlamda rastgele herhangi bir veri kümesinin daha büyük bir kümenin daha sonra çürüteceği konusunda belirgin bir önyargı gösterebileceği için belirleyici değildir.
KeithS

1
Bu, zaman zaman ve tahmin edilemez bir şekilde kırılacak bir testtir. Bunu istemiyorsun Dürüst olmak gerekirse, amacımı yanlış anladın. Randomiser dediğiniz şeyin içinde bir yerde, rasgele bir sayı üreten kod satırı olmalı, değil mi? Bu çizgi, bir randomizatör olarak adlandırdığım şeydir ve randomizatör olarak adlandırdığınızın geri kalanı ("rastgele" verilere dayalı tarihlerin dağılımı) test etmek istediğiniz şeydir. Yoksa bir şey mi kaçırıyorum?
pdr

rastgele dizilerin (korelasyon, blok korelasyon, ortalama, standart sapmalar vb.) istatistiksel olarak uygun bir şekilde ölçülmesi, yalnızca gerçekten küçük örnekler alırsanız beklentilerinizi karşılayamaz. Örnekleme setlerinizi ve / veya izin verilen hata çubuklarınızı
arttırın

1
"hatta bazı seviyelerde önyargı" Eğer iyi bir PRNG kullanırsanız, o zaman gerçek rastgelelikten ayrı olarak söyleyebilecek herhangi bir test (gerçekçi hesaplama sınırları ile) bulamazsınız. Bu yüzden pratikte, iyi bir PRNG'nin hiçbir şekilde önyargısı olmadığı varsayılabilir.
CodesInChaos

23

Bu aptalca bir cevap gibi gelecektir, ama onu dışarıya atacağım çünkü daha önce de böyle gördüm:

Kodunuzu PRNG'den ayırın - randomizasyon tohumunu randomizasyon kullanan tüm kodlara geçirin. Ardından, 'çalışma' değerlerini tek bir tohumdan (veya bunun birden fazla tohumundan daha iyi hissetmenizi sağlayacak) belirleyebilirsiniz. Bu, size büyük sayılar yasasına güvenmek zorunda kalmadan kodunuzu uygun bir şekilde test etme imkanı verecektir.

Kulağa kulağa hoş geliyor ama ordunun yaptığı budur (ya öyle ya da gerçekten rastgele olmayan bir 'rasgele masa' kullanıyorlar)


Aynen: eğer bir algoritmanın unsurunu test edemiyorsanız, soyutlayın ve alay edin
Steve Greatrex

Deterministik bir tohum değeri belirtmedim; bunun yerine, "rastgele" öğeyi tamamen kaldırdım, böylece belirli PRNG algoritmasına güvenmem bile gerekmiyordu. Çok sayıda eşit dağılmış sayılar verdiğimde, birlikte kullandığım algoritmanın önyargıya neden olmadan daha küçük bir aralıkta olabileceğini test edebildim. PRNG'nin kendisi onu geliştiren kişi tarafından yeterince test edilmelidir (RNGCryptoServiceProvider kullanıyorum).
KeithS

"Rastgele tablo" yaklaşımıyla ilgili olarak, "tersinir" sayı üreten bir algoritma içeren bir test uygulaması da kullanabilirsiniz. Bu, PRNG'yi "geri sarmanıza" ya da son N çıktının ne olduğunu görmek için sorgulamanıza izin verir. Bazı senaryolarda çok daha derinlemesine hata ayıklamaya izin verirdi.
Darien

Bu o kadar aptalca değil - Google’ın Spanner testlerinde başarısızlık enjeksiyonunu kağıtlarına göre yeniden üretmek için kullandığı yöntem aynıydı :)
Akshat Mahajan

6

“Rastgele mi (yeterli)” inanılmaz derecede ince bir soru olarak ortaya çıkıyor. Kısa cevap, geleneksel bir birim testinin kesin olarak kesmeyeceğidir - bir grup rastgele değer üretmeniz ve bunları ihtiyaçlarınız için yeterince rasgele olduklarına dair yüksek güven veren çeşitli istatistiksel testlere sunmanız gerekir.

Bir kalıp olacak - sonuçta psuedo-rasgele sayı üreteçlerini kullanıyoruz. Ancak bir noktada işler uygulamanız için "yeterince iyi" olacaktır (yeterince iyi olan yerlerde bir uçtaki oyunlar arasında, nispeten basit üreticilerin yeterli olduğu yerlerde, gerçekten belirlemek için gerçekten mümkün olan kriptografiye kadar şifreleme kadar) kararlı ve iyi donanımlı bir saldırgan tarafından).

Http://en.wikipedia.org/wiki/Randomness_tests adresindeki Wikipedia makalesi ve takip bağlantıları daha fazla bilgiye sahiptir.


Vasat PRNG'ler bile herhangi bir istatistiksel testte herhangi bir bildiri göstermeyeceklerdir. İyi PRNG'ler için onları gerçek rastgele sayılardan ayırt etmek neredeyse imkansızdır.
CodesInChaos

4

Senin için iki cevabım var.

=== İLK CEVAP ===

Sorunuzun başlığını gördüğümde, içeri girip çözümü önerdim. Benim çözümüm, başkalarının önerdiği ile aynıydı: rastgele sayı üreticinizi alay etmek. Sonuçta, iyi ünite testleri yazmak için bu numarayı gerektiren birkaç farklı program oluşturdum ve kodlamada rastgele sayılarla standart bir uygulama yapmayı başarabiliyorum.

Ama sonra sorunuzu okudum. Ve tarif ettiğiniz belirli bir konu için cevap bu değil. Sorununuz, rastgele sayılar kullanan bir işlemi tahmin edilebilir hale getirmeniz gerekmedi (bu yüzden test edilebilir). Aksine, probleminiz algoritmanızın RNG'nizden rastgele çıktısını rastgele çıktısını algoritmanızdaki sınırlar içinde tekdüze çıktıyla eşleştirdiğini doğrulamaktı - temel RNG tekdüze ise eşit dağıtılmış denetim zamanları ile sonuçlanacağını ( problem kısıtlamaları).

Bu gerçekten zor (ama oldukça iyi tanımlanmış) bir problem. Bu, İLGİNÇ bir problem olduğu anlamına gelir. Hemen bunun nasıl çözüleceği konusunda gerçekten harika fikirler düşünmeye başladım. Sıcak bir programcı olduğumda, bu fikirlerle bir şeyler yapmaya başlamış olabilirim. Ama artık sıcak çekim programcısı değilim ... Artık daha deneyimli ve daha yetenekli olduğumu seviyorum.

Bu yüzden zor soruna dalmak yerine kendi kendime düşündüm: Bunun değeri nedir? Ve cevap hayal kırıklığı yarattı. Hatalarınız çoktan çözüldü ve gelecekte bu konuda titiz davranacaksınız. Dış koşullar sorunu tetikleyemez, yalnızca algoritmanızda değişiklik yapar. SADECE bu ilginç sorunun üstesinden gelmenin nedeni TDD (Test Odaklı Tasarım) uygulamalarını karşılamaktı. Öğrendiğim bir şey varsa, değerli olmadığı zaman herhangi bir uygulamaya kör bir şekilde bağlı kalmanın sorunlara yol açtığıdır. Benim önerim şudur: Sadece bunun için bir test yazmayın ve devam edin.


=== İKİNCİ CEVAP ===

Vay ... ne güzel bir sorun!

Burada yapmanız gereken, inceleme tarihlerini ve saatlerini seçmek için algoritmanızın, kullandığı RNG düzgün dağılmış sayılar üretiyorsa, eşit dağıtılmış (sorun kısıtlamaları dahilinde) çıktı üreteceğini doğrulayan bir test yazmaktır. İşte zorluk derecesine göre sıralanan çeşitli yaklaşımlar.

  1. Kaba kuvvet uygulayabilirsiniz. Sadece algoritmayı giriş olarak gerçek bir RNG ile birlikte bir kaç kez TAMAM çalıştırın. Çıktı sonuçlarını kontrol ederek eşit dağılım gösterip göstermediklerini kontrol edin. Eğer dağıtım, belirli bir eşikten daha mükemmel bir şekilde tekdüze değişirse, testte başarısız olmanız ve problemleri yakalamanız için eşyanın ÇOK düşük ayarlanamaması gerekir. Bu, hatalı pozitif (rastgele şans eseri bir test hatası) olasılığının çok küçük (orta büyüklükteki bir kod tabanı için <% 1; daha az olması için bile <% 1) olduğundan emin olmak için çok sayıda çalışmaya ihtiyaç duyacağınız anlamına gelir. büyük bir kod tabanı).

  2. Algoritmanızı, tüm RNG çıktısını bir girdi olarak birleştiren, daha sonra da çıktı olarak inceleme zamanları üreten bir fonksiyon olarak düşünün. Bu fonksiyonun parça parça sürekli olduğunu biliyorsanız, o zaman mülkünüzü test etmenin bir yolu vardır. RNG'yi takılabilir bir RNG ile değiştirin ve algoritmayı birçok kez çalıştırın, düzgün dağılmış RNG çıktısı üretin. Eğer kodunuz 2 RNG çağrısı gerektiriyorsa, her biri [0..1] aralığında, testin algoritmayı 100 kez çalıştırıp, değerleri döndürerek [(0.0,0.0), (0.0.0.1), (0.0, 0.2), ... (0.0.0.9), (0.1.0.0), (0.1.0.1), ... (0.9.0.9)]. Ardından, 100 çalışmanın çıktısının (yaklaşık olarak) izin verilen aralıkta eşit bir şekilde dağılmış olup olmadığını kontrol edebilirsiniz.

  3. Algoritmayı GERÇEKTEN güvenilir bir şekilde doğrulamanız gerekiyorsa ve algoritma hakkında varsayımlar yapamıyorsanız VEYA çok sayıda kez çalıştırıyorsanız, o zaman soruna hala saldırabilirsiniz, ancak algoritmayı nasıl programladığınızla ilgili bazı kısıtlamalara ihtiyaç duyabilirsiniz. . Check out PYPY ve Nesne Uzay örnek olarak yaklaşım. Aslında algoritmayı çalıştırmak yerine, çıktı dağılımının şeklini hesaplayan bir nesne alanı yaratabilirsiniz (RNG girişinin tekdüze olduğu varsayılarak). Elbette bu, böyle bir araç inşa etmenizi ve algoritmanızın PyPy'de veya derleyicide ciddi değişiklikler yapmanın ve kodu analiz etmek için kullanmanın kolay olduğu başka bir araçta oluşturulmasını gerektirir.


3

Ünite testleri için, rastgele jeneratörü tüm köşe kasalarını kapsayan öngörülebilir sonuçlar üreten bir sınıfla değiştirin . Yani, sözde randomizerinizin mümkün olan en düşük değeri ve mümkün olan en yüksek değeri üretmesini ve aynı sonucun art arda birkaç kez üretilmesini sağlayın.

Ünite testlerinizin örneğin Random.nextInt (1000) 0 veya 999 döndürdüğünde meydana gelen hataları tek tek gözden kaçırmasını istemezsiniz.


3

Sevcikova ve arkadaşlarının: "Stokastik Sistemlerin Otomatik Test Edilmesi: İstatistiksel Olarak Topraklanmış Bir Yaklaşım" ( PDF ).

UrbanSim simülasyon platformu için metodoloji çeşitli test durumlarında uygulanmaktadır .


Orada güzel şeyler var.
KeithS

2

Basit bir histogram yaklaşımı iyi bir ilk adımdır, fakat rastgeleliği kanıtlamak için yeterli değildir. Tek tip bir PRNG için, ayrıca (en azından), 2 boyutlu bir dağılım grafiği oluşturur (x, önceki değer ve y, yeni değerdir). Bu arsa da aynı şekilde olmalıdır. Bu sizin durumunuzda karmaşık bir durum çünkü sistemde kasıtlı olarak doğrusal olmayan şeyler var.

Benim yaklaşımım:

  1. kaynak PRNG'nin yeterince rastgele olduğunu (standart istatistik önlemleri kullanarak) doğrulayın (veya belirli bir şekilde alın).
  2. Sınırlandırılmamış bir PRNG-to-time dönüşümünün, çıktı alanı üzerinde yeterince rastgele olduğunu doğrulayın (bu, dönüşümde önyargı bulunmadığını doğrular). Basit birinci dereceden homojenlik testiniz burada yeterli olmalıdır.
  3. Sınırlandırılmış durumların yeterince düzgün olduğunu doğrulayın (geçerli kutular üzerinde basit bir birinci dereceden homojenlik testi).

Bu testlerin her biri istatistikseldir ve yanlış pozitifleri ve yüksek derecede güven ile yanlış negatifleri önlemek için çok sayıda örnek nokta gerektirir.

Dönüşüm / kısıtlama algoritmasının niteliği ile ilgili olarak:

Verilen: p -rasgele değer üretme metodu, p = 0 <= p <= M

İhtiyaç: çıkış y (muhtemelen süreksiz) aralığında 0 <= y <= N <= M

Algoritma:

  1. hesaplamak r = floor(M / N), yani, giriş aralığına uyan tam çıkış aralıklarının sayısını.
  2. p için kabul edilebilir maksimum değeri hesaplayın :p_max = r * N
  3. için değerleri meydana p az bir değere kadar veya eşit p_maxbulunursa
  4. hesaplamak y = p / r
  5. eğer y kabul edilebilirse, geri gönderin, aksi takdirde 3. adımla tekrarlayın

Anahtar, düzgün olmayan şekilde katlamak yerine kabul edilemez değerleri atmaktır.

sözde kodda:

# assume prng generates non-negative values
def randomInRange(min, max, prng):
    range = max - min
    factor = prng.max / range

    do:
        value = prng()
    while value > range * factor
    return (value / factor) + min

def constrainedRandom(constraint, prng):
    do:
        value = randomInRange(constraint.min, constraint.max, prng)
    while not constraint.is_acceptable(value)

1

Kodunuzun başarısız olmadığının doğrulanması veya doğru yerlere doğru istisnalar atmanın yanı sıra geçerli bir giriş / yanıt çifti oluşturabilirsiniz (bunu manuel olarak hesaplayarak da yapabilirsiniz), testte girişi besleyin ve beklenen yanıtı döndürdüğünden emin olun. Harika değil, ama yapabileceğin tek şey bu. Ancak, sizin durumunuzda gerçekten rastgele değil, zamanlamanızı oluşturduktan sonra kuralların uygunluğunu test edebilirsiniz - haftada 3 teftiş yapılmalı, 9-9 arasında; Muayene gerçekleştiğinde kesin zamanları test etmek için gerçek bir ihtiyaç veya yetenek yoktur.


1

Gerçekten birkaç kez çalıştırıp, istediğiniz dağıtımı alıp almadığınızı görmekden daha iyi bir yol yok. İzin verilen 50 potansiyel denetim planınız varsa, testi 500 defa çalıştırır ve her bir programın 10 defaya yakın kullanıldığından emin olursunuz. Rasgele jeneratör tohumlarınızı daha belirleyici yapmak için kontrol edebilirsiniz ancak bu, testlerinizi uygulama detaylarıyla daha sıkı bir şekilde birleştirmenizi sağlayacaktır.


Fakat eğer gerçekten rastlantısalsa, o zaman zaman zaman, bazı programlar hiç kullanılmayacak; ve zaman zaman, bazı programlar 20 defadan fazla kullanılacaktır. Her bir programın "10'a yakın" olarak kullanıldığını nasıl test etmek istediğinizi bilmiyorum, ancak burada test ettiğiniz şartlar ne olursa olsun, programın çalışması için çalışırken bazen başarısız olan bir sınava sahip olacaksınız.
Dawood, Monica

@DawoodibnKareem yeterli bir örneklem büyüklüğüne (ve tekdüzelik üzerine makul sınırlara sahip), testin milyarlarca olarak başarısız olma ihtimalini azaltabilirsiniz. Genelde bunun gibi istatistikler n ile üstel olduğundan, bu rakamlara ulaşmayı beklediğinizden daha az zaman alır.
mbrig

1

Somut bir tanımı olmayan kötü bir durumu test etmek mümkün değildir. Oluşturulan tarihler tüm testleri geçerse teorik olarak uygulamanız doğru çalışıyor demektir. Bilgisayar, tarihlerin "yeterince rasgele" olup olmadığını söyleyemez, çünkü böyle bir test için kriterleri kabul edemez. Tüm testler başarılı olursa ancak uygulamanın davranışı hala uygun değilse, test kapsamınız ampirik olarak yetersizdir (TDD perspektifinden).

Benim görüşüme göre, elinizden gelenin en iyisi, dağıtımın insan kokusu testini geçmesi için bazı keyfi tarih oluşturma kısıtlamaları uygulamaktır.


2
Otomatik testler yoluyla rastgeleliği kesinlikle belirleyebilirsiniz. Yeterince fazla sayıda örnek üretiyorsunuz ve sistemdeki önyargıları tespit etmek için standart rastgelelik testleri yapıyorsunuz. Bu oldukça standart bir undergrad programlama alıştırmasıdır.
Frank Szczerba

0

Sadece randomizerinizin çıktısını kaydedin (sözde veya kuantum / kaotik veya gerçek dünya). Ardından, test gereksinimlerinize uyan ya da ünite test durumlarınızı oluştururken olası sorunları ve hataları ortaya çıkaran "rastgele" dizileri kaydedin ve tekrarlayın.


0

Bu durum, Mülk Tabanlı Testler için ideal görünüyor .

Özet olarak, test çerçevesinin test altındaki kod için girdi oluşturduğu ve test iddialarının çıktıların özelliklerini doğruladığı bir test şeklidir . Çerçeve daha sonra test edilen koda "saldırmak" ve onu bir hataya sıkıştırmak için yeterince akıllı olabilir. Çerçeve genellikle rastgele sayı üreteci tohumunuzu kaçırmanız için de yeterince akıllı. Genellikle, çerçeveyi en fazla N test vakası oluşturacak şekilde veya en fazla N saniyede çalışacak şekilde yapılandırabilir ve başarısız test senaryolarını son testten hatırlayabilir ve bunları daha önce daha yeni kod sürümüne göre yeniden çalıştırabilirsiniz. Bu, geliştirme sırasında hızlı yineleme döngüsüne ve bant içinde / CI'de yavaş, kapsamlı testlere olanak sağlar.

İşte sumişlevi test eden (aptal, başarısız) bir örnek :

@given(lists(floats()))
def test_sum(alist):
    result = sum(alist)
    assert isinstance(result, float)
    assert result > 0
  • Test çerçevesi aynı anda bir liste oluşturacak
  • listenin içeriği kayan nokta sayıları olacaktır
  • sum çağrılır ve sonucun özellikleri doğrulanır
  • sonuç her zaman yüzer
  • sonuç olumlu

Bu test, bir grup "böcek" bulacaktır sum(eğer hepsini kendi başınıza tahmin edebildiyseniz, yorum yapın):

  • sum([]) is 0 (int, şamandıra değil)
  • sum([-0.9]) negatif
  • sum([0.0]) kesinlikle olumlu değil
  • sum([..., nan]) is nan hangi pozitif değil

Varsayılan ayarlarla, hpythesisTDD için iyi olan 1 "kötü" giriş bulunduktan sonra testi iptal eder. "Kötü" girişlerin çoğunu rapor edecek şekilde yapılandırmanın mümkün olduğunu düşündüm, ancak şimdi bu seçenekleri bulamıyorum.

OP durumunda, onaylanan özellikler daha karmaşık olacaktır: mevcut olan muayene türü A mevcut, muayene türü A haftada üç kez, muayene zamanı B her zaman saat 12: 00'de, muayene türü C 9'dan 9'a kadar, [verilen program bir hafta içindir] türlerin muayenesi A, B, C hepsi mevcut vb.

En iyi bilinen kütüphane Haskell için QuickCheck'tir , diğer dillerde bu tür kütüphanelerin listesi için aşağıdaki Wikipedia sayfasına bakın:

https://en.wikipedia.org/wiki/QuickCheck

Hipotez (Python için) bu tür testler hakkında iyi bir yazıya sahiptir:

https://hypothesis.works/articles/what-is-property-based-testing/


-1

Birim testi, rastgele tarihlerin geçerli olup olmadığını veya başka bir rastgele tarihin seçilmesi gerekip gerekmediğini belirleyen mantıktır.

Rasgele bir tarih oluşturucuyu bir sürü tarih almaktan ve uygun bir şekilde rastgele olup olmadıklarına karar vermekten kısa bir şekilde test etmenin bir yolu yoktur.


-1

Amacınız, ünite testleri yazmak ve bunları geçmek değil, programınızın gereksinimlerine uygun olduğundan emin olmaktır. Bunu yapmanın tek yolu, gereksinimlerinizi en başta tam olarak belirlemektir. Örneğin, "rastgele zamanlarda üç haftalık denetimden" bahsettiniz. Gereksinimler şunlardır: (a) Beklenmedik bir şekilde denetlenmek istemeyen kişiler tarafından öngörülemeyen zamanlarda 3 denetim (2 veya 4 değil), (b) ve (c) birbirine çok yakın olmamak. Beş dakika aradaki iki denetim muhtemelen anlamsız, belki de birbirinden çok uzak değil.

Yani gereksinimleri benden daha kesin olarak yazıyorsun. (a) ve (c) kolaydır. (B) için, bir sonraki incelemeyi tahmin etmeye çalışan ve birim testini geçmeye çalışan olabildiğince akıllıca bir kod yazabilirsiniz, bu kod saf tahminden daha iyi tahmin edemez.

Ve tabii ki, eğer teftişleriniz gerçekten rastlantısalsa, herhangi bir tahmin algoritmasının tamamen tesadüfen doğru olabileceğinin farkında olmalısınız, bu nedenle, sizin ve birim testlerinizin gerçekleşmesi durumunda paniğe kapılmadığından emin olmalısınız. Belki birkaç test daha yapabilirim. Rasgele sayı üretecini test etmekten rahatsız olmazdım, çünkü sonunda sayılan kontrol programı ve nasıl yaratıldığı önemli değil.


Hayır sadece hayır. Birim testleri programın kendi gereksinimlerini karşıladığını kanıtlar, bu yüzden ikisi aynıdır. Ve ben rasgele algoritmalar tersine mühendislik için prediktif yazılım yazma işinde değilim. Olmasaydım, size anlatmazdım, anahtarlarını tahmin ederek ve en yüksek teklifi verenin sırrını satarak güvenli web siteleri kırmaya öldürürüm. İşim, kısıtlayıcı olan ve kısıtlamalar dahilinde öngörülemeyen zamanlar yaratan bir zamanlayıcı yazıyor ve bunu yaptığımı kanıtlamak için deterministik testlere ihtiyacım var, oldukça emin olduğumu söyleyen olasılıklı olanları değil.
KeithS
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.