Rasgeleliği nasıl test etmeliyim?


127

Bir dizideki öğeleri rastgele karıştırmak için bir yöntem düşünün. Bunun çalıştığından emin olmak için basit ama sağlam bir ünite testi nasıl yazardınız?

Her ikisi de gözle görülür kusurları olan iki fikir buldum:

  • Diziyi karıştırın, ardından sırasının öncekinden farklı olduğundan emin olun. Bu kulağa hoş geliyor, ancak karışık aynı sırayla karıştırmaya başlarsa başarısız olur. (Mümkün değil, mümkün.)
  • Diziyi sabit bir tohumla karıştırın ve önceden belirlenmiş çıktıya karşı kontrol edin. Bu, her zaman aynı tohum verilen aynı değerleri döndürerek rastgele işlevine dayanır. Ancak, bu bazen bir geçersiz varsayım .

Zar rulolarını simüle eden ve rastgele bir sayı döndüren ikinci bir fonksiyon düşünün. Bu işlevi nasıl test edersiniz? Bu işlevi nasıl test edersiniz?

  • asla verilen sınırların dışında bir sayı döndürmez?
  • geçerli bir dağıtımdaki sayıları döndürür? (Bir kalıp için tek tip, çok sayıda zar için normal.)

Sadece bu örnekleri değil, genel olarak rastgele kod öğelerini de sınama konusunda fikir veren cevaplar arıyorum. Ünite testleri burada doğru çözüm mü? Eğer değilse, ne tür testler?


Sadece ben değilim herkesin aklını hafifletmek için değil kendi rasgele sayı üreteci yazma.


35
Sıkı kavrama kafasını gösterir. Rasgele sayılar üreten nesneyi iletin. Daha sonra test sırasında, destenin karışıklıktan sonra nasıl göründüğünü bildiğiniz belirli bir sayı setini üreten bir nesneyi geçebilirsiniz. Rasgele sayı üreticinizin rastgeleliğini ayrı ayrı test edebilirsiniz.
Martin York

1
Shuffle (java Collections.shuffle () veya benzeri) için mevcut bir kütüphane yordamını kullanmayı düşünürdüm. Kusurlu bir karıştırma algoritması yazmak konusunda developer.com/tech/article.php/616221/… adresinde okunması gereken bir uyarıcı hikaye var . Bir d6 () işlevi yazmak için, aralığın dışında bir sayı üretmeyeceğinden emin olmak için yeterli bir test yapılır ve daha sonra dağılım üzerinde ki kare testi yapılır (ki kare kare sıralı rasgele sekanslara karşı oldukça hassastır). Seri korelasyon katsayısına da bakın.

“Bu, her zaman aynı tohum verilen aynı değerleri döndüren rastgele fonksiyona dayanır. Ancak, bu bazen geçersiz bir varsayımdır.” Bağlantıyı takip ettim ve geçersiz varsayımı göremiyorum. Oldukça açık bir şekilde şöyle diyor: "Eğer aynı tohum tekrar tekrar kullanılıyorsa, aynı sayı dizileri üretilir."
Kyralessa

@Kyralessa "Rastgele sınıftaki rasgele sayı oluşturucunun .NET Framework'ün ana sürümlerinde aynı kalması garanti edilmez." Yani büyük bir endişe değil, yine de dikkate alınması gereken bir şey.
dlras2

4
@Kyralessa Bu teklifin önemli yarısını kaçırdım: "Sonuç olarak, uygulama kodunuz aynı tohumun .NET Framework'ün farklı sürümlerinde aynı sözde rastgele sırayla sonuçlanacağını varsaymamalıdır."
dlras2

Yanıtlar:


102

Ünite testlerinin rastgelelik testi için doğru araç olduğunu sanmıyorum. Birim testi bir yöntem çağırmalı ve döndürülen değeri (veya nesne durumunu) beklenen değere göre test etmelidir. Test rastgeleliği ile ilgili sorun, test etmek istediğiniz şeylerin çoğu için beklenen bir değer bulunmamasıdır. Belirli bir tohumla test edebilirsiniz, ancak bu yalnızca tekrarlanabilirliği test eder . Dağılımın ne kadar rastgele olduğunu veya hiç rastgele olup olmadığını ölçmenin hiçbir yolunu size vermez .

Neyse ki, Diehard Rastgele Testleri Bataryası gibi yapabileceğiniz birçok istatistiksel test vardır . Ayrıca bakınız:

  1. Bir sözde rasgele sayı üreteci birim test nasıl?

    • Steve Jessop , kullandığınız aynı RNG algoritmasının test edilmiş bir uygulamasını bulmanızı ve çıktısını seçilen tohumlarla kendi uygulamanızla karşılaştırmanızı önerir.
    • Greg Hewgill , KBB istatistik testlerini önermektedir .
    • John D. Cook , Donald Knuth'un 2. sayısı olan Seminumerical Algorithms'te bahsedilen Kolmogorov-Smirnov testinin bir uygulamasını içeren CodeProject makalesi Simple Random Number Generation adlı okuyucusuna atıfta bulunuyor.
    • Birkaç kişi, üretilen sayıların dağılımının tek tip olduğunu test eder, Ki-kare testi ve ortalama ve standart sapmanın beklenen aralıkta olduğunu test eder. (Dağılımı tek başına test etmenin yeterli olmadığını unutmayın. [1,2,3,4,5,6,7,8] tek tip bir dağıtımdır, ancak kesinlikle rastgele değildir.)
  2. Rastgele sonuç veren fonksiyonlarla Birim Testi

    • Brian Genisio, RNG'nizi taklit etmenin testlerinizi tekrarlanabilir kılmak için bir seçenek olduğuna işaret eder ve C # örnek kodu sağlar.
    • Yine, birkaç kişi daha tekrarlanabilirlik için sabit tohum değerlerini ve düzgün dağılım, Ki-kare, vb.
  3. Birim Testi Rastgeleliği , doğası gereği tekrarlanamayan bir şeyi test etmeye çalışırken zaten dokunulan zorlukların çoğundan bahseden bir wiki makalesidir. Ondan aldığım ilginç bir şey şuydu:

    Daha önce bir değerler dosyasının rastgeleliğini ölçmek için bir araç olarak kullanılan winzip'i gördüm (tabii ki dosya ne kadar küçükse o kadar az rastgele olur).


İstatistiksel rastgelelik için bir başka iyi test takımı fourmilab.ch/random 'de bulunur .

1
Cevabın tam olması için gönderdiğiniz linklerden bazılarını özetleyebilir misiniz?
dlras2

@DanRasmussen Elbette, bunu haftasonu boyunca yapacak zamanım olacak.
Kertenkele Bill

4
“… Rastgelelik ile ilgili sorun beklenen bir değerin olmaması…” - “beklenen değer” in istatistikte iyi tanımlanmış bir terim olduğu göz önüne alındığında, ne kadar ironik. Demek istediğin bu olmasa da, doğru çözüme işaret ediyor: bir algoritmanın çok yüksek olasılıkla çalışıp çalışmadığını belirlemek için rastgele örnekleme ve istatistiksel testlerle birleştirilmiş istatistiksel dağılımların bilinen özelliklerini kullanmak . Evet, bu klasik bir ünite testi değil, ancak en kolay durumda, beklenen değerin dağılımına baktığından bahsetmek istedim .
Konrad Rudolph

2
Ulusal Standartlar ve Teknoloji Enstitüsü (NIST) tarafından geliştirilen İstatistiksel Test Paketini (STS) içeren Dieharder'daki ünlü Diehard Rastgele Testler Bataryası'nın güncellenmiş bir sürümü var. Ubuntu'da ve muhtemelen diğer dağıtımlarda kullanıma hazır: phy.duke.edu/~rgb/General/dieharder.php
nealmcb

21

1. Birim algoritmanızı test edin

İlk soru için, algoritmanızın sonucunu bildiğiniz, rastgele sayılar dizisini beslediğiniz sahte bir sınıf oluşturacağım. Bu şekilde , rastgele işlevinizin üzerine kurduğunuz algoritmanın çalıştığından emin olursunuz . Yani çizgileri boyunca bir şey:

Random r = new RandomStub([1,3,5,3,1,2]);
r.random(); //returns 1
r.random(); //returns 3
...

2. Rastgele fonksiyonunuzun mantıklı olup olmadığını görün

Birim testine birden çok kez çalışan bir test eklemelisiniz ve sonuçları

  • belirlediğiniz sınırlar dahilindesiniz (yani, bir zar rulosu 1 ile 6 arasında) ve
  • makul bir dağılım gösterirler (çoklu testler gerçekleştirin ve dağılımın beklediğinizden% x oranında olup olmadığına bakın, örn. zar rulosu için 2% 10 ile% 20 arasında bir artış görmelisiniz (1/6 =% 16.67). 1000 kez yuvarlandığın zaman).

3. Algoritma ve rastgele fonksiyon için entegrasyon testi

Dizininizin orijinal sıralamada ne sıklıkla sıralanmasını beklersiniz? Birkaç yüz kez sıralama yapın ve sıralamanın yalnızca% x'inin değişmediğini belirtin.

Bu aslında zaten bir entegrasyon testidir, algoritmayı rastgele işleviyle birlikte test ediyorsunuz. Gerçek rastgele işlevi kullandığınızda, artık tek bir deneme çalıştırmasıyla elde edemezsiniz.

Tecrübelerimden (genetik bir algoritma yazdım), algoritmanızın birim testini birleştirerek, rastgele fonksiyonunuzun dağılım testini ve entegrasyon testini bir araya getireceğimi söyleyebilirim.


14

Unutulmuş görünen PRNG'lerin bir yönü, tüm özelliklerinin doğada istatistiksel olmasıdır: bir dizinin karıştırılmasının, başladığınızdan farklı bir permütasyona neden olacağını bekleyemezsiniz. Temel olarak, normal bir PRNG kullanıyorsanız, garanti ettiğiniz tek şey basit bir desen kullanmamasıdır (umarım) ve hatta döndürdüğü sayı kümesi arasında dağılım gösterdiğidir.

Bir PRNG için uygun bir test en az 100 kez çalıştırmayı ve ardından çıktının dağılımını kontrol etmeyi içerecektir (bu sorunun ikinci kısmına doğrudan bir cevaptır).

İlk soruya verilen cevap hemen hemen aynı: {1, 2, ..., n} ile testi yaklaşık 100 kez çalıştırın ve her bir elemanın her pozisyonda kaç kez olduğunu sayın. Karıştırma yöntemi herhangi bir iyiyse, hepsinin kabaca eşit olması gerekir.

Tamamen farklı bir mesele, şifreleme dereceli PRNG'lerin nasıl test edileceğidir. Bu, ne yaptığınızı gerçekten bilmiyorsanız, muhtemelen oturmamanız gereken bir konudur. İnsanların, sadece birkaç 'optimizasyon' veya önemsiz düzenlemeyle iyi şifreleme sistemlerini yok ettiği (okumak: felaket delikleri açmak) bilinmektedir .

EDIT: Soruyu, en iyi cevabı ve kendime ait olanları tamamen okudum. Yaptığım noktalar hâlâ geçerli olsa da, Lizard'ın cevabını Bill’in ikinci sırasına koyardım. Birim testler doğası gereği Boole'dur - ya başarısız olurlar ya da başarılı olurlar ve bu nedenle bir PRNG'nin (ya da bir PRNG kullanan bir yöntem) özelliklerinin "ne kadar iyi" olduğunu test etmek için uygun değillerdir, çünkü bu sorunun cevabı niceldir. , kutup yerine.


1
Bence her bir elemanın her bir pozisyondaki sayısının kabaca eşit olması gerektiği anlamına geliyor . Sürekli olarak tamamen eşitlerse, bir şeyler çok yanlış olur.
octern

@octern Teşekkürler, bunu nasıl yazabilirim bilmiyorum ... şu ana kadar tamamen yanlıştı ...
K.Steff

6

Bunun iki kısmı vardır: randomizasyon testi ve randomizasyon kullanan şeyleri test etmek.

Randomizasyonun test edilmesi nispeten kolaydır. Rastgele sayı üretecinin süresinin beklediğiniz gibi olup olmadığını (bazı eşik içinde birkaç rastgele tohum kullanarak birkaç örnek için) ve çıktının büyük bir örneklem büyüklüğüne dağılımının beklediğiniz gibi olduğunu kontrol edersiniz. olması (bazı eşiklerde).

Randomizasyon kullanan şeyleri test etmek en iyi deterministic psuedo-random number generator ile yapılır. Rastgeleleştirmenin çıktısı, tohum (girdileri) bazında bilindiğinden, daha sonra beklenen çıktılara karşı girdilere göre testi normal yapabilirsiniz. Eğer RNG'niz deterministik değilse , determinist olan (veya sadece rastgele olmayan) bir cihazla alay edin. Randomizasyonu, tüketen koddan izole ederek test edin.


6

Birkaç kez çalışmasına ve verilerinizi görselleştirmesine izin verin .

İşte Kod Yazma Korkusundan bir karışıklık örneği , algoritmanın uygun olup olmadığını görebilirsiniz:

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

Her olası öğenin en az bir kez döndürüldüğünü (sınırlar TAMAM) ve dağıtımın TAMAM olduğunu görmek kolaydır.


1
+1 görselleştirme anahtarıdır. Blok şifreleme makalesinin ECB bölümündeki bir penguenin resmi olan örneği her zaman sevdim ). Otomatikleştirilmiş bir yazılım nadiren bu tür
düzenleri

Eh? Bu görselleştirmenin amacı, dağıtımın tamam olmadığını göstermektir . Saf karışma algoritması, belirli siparişleri diğerlerinden çok daha muhtemel kılar . 2341, 2314, 2143 ve 1342 barların sağda ne kadar daha geniş olduğuna dikkat edin?
hvd

4

Genel işaretçiler Rasgele girdi alan kodlarla çalışırken yararlı buldum: Beklenen rastgeleliğin kenar durumlarını kontrol edin (maks. Ve min değerleri ile varsa maks. + 1 ve min-1 değerleri). Kesirli bir değerin fonksiyonu bozabileceği durumlar için sayıların çarpma noktalarına (yani -1, 0, 1 veya 1'den büyük, 1'den küçük ve negatif olmayan) yerleri kontrol edin. İzin verilen girişin dışında birkaç yeri kontrol edin. Birkaç tipik durumu kontrol edin. Ayrıca rasgele bir giriş ekleyebilirsiniz, ancak testin her çalıştırılışında aynı değerin test edilmediği istenmeyen yan etkiye sahip olan bir birim testi için (bir tohum yaklaşımı işe yarayabilir, tohumdan ilk 1000 rastgele sayıyı test edin) S veya somesuch).

Rastgele bir fonksiyonun çıktısını test etmek için hedefi belirlemek önemlidir. Kartlar halinde, sonuçta 52 kartın hepsinin görünüp görünmediğini veya başka bir hedefin (belki de bu listenin tümü ve daha fazlası) olup olmadığını belirlemek için 0-1 rasgele üretecinin bütünlüğünü test etmek amaç mıdır?

Spesifik örnekte, rasgele sayı üreticinizin opak olduğunu varsaymanız gerekir (işletim sistemi yazmadığınız sürece, işletim sistemi sistem çağrısı veya malloc ünitesini test etmenin bir anlamı yoktur). Rastgele sayı üretecini ölçmek faydalı olabilir, ancak hedefiniz rastgele bir üreteç yazmak değil, yalnızca her seferinde 52 kart aldığınızı ve sıralarını değiştirdiklerini görmek için.

Burada gerçekten iki test görevi olduğunu söylemenin uzun bir yolu var: RNG'nin doğru dağıtımı ürettiğini test etmek ve kart karışık kodunuzun bu RNG'yi rastgele sonuçlar üretmek için kullanıp kullanmadığını kontrol etmek. RNG yazıyorsanız, dağıtımınızı kanıtlamak için istatistiksel analiz kullanın, kart karıştırıcısını yazıyorsanız, her çıktıda 52 tekrarlanmayan kart olduğundan emin olun (kullandığınız incelemeyle test etmek için daha iyi bir durum RNG).


4

Güvenli rasgele sayı üreteçlerine güvenebilirsiniz

Sadece korkunç bir düşüncem vardı: kendi rasgele sayı üreticini yazmıyorsun değil mi?

Olmadığınızı varsayalım, o zaman başkalarının kodunu ( çerçevenizin uygulaması gibi) değil , sorumlu olduğunuz kodu test etmeniz gerekir SecureRandom.

Kodunuzu test etme

Kodunuzun doğru şekilde yanıt verdiğini test etmek için, rastgele sayıları üretmek için düşük görünürlük yöntemini kullanmak normaldir, böylece bir birim test sınıfı tarafından kolayca geçersiz kılınabilir. Bu geçersiz kılma yöntemi, rasgele sayı üretecini etkin bir şekilde atar ve size ne ve ne zaman üretildiği konusunda tam kontrol sağlar. Sonuç olarak, ünite testinin amacı olan kodunuzu tam olarak kullanabilirsiniz.

Açıkçası, en son koşulları kontrol edecek ve karıştırma işleminin tam olarak algoritmanızın uygun girdilerin verdiği şekilde gerçekleştirdiği gibi gerçekleşmesini sağlayacaksınız.

Güvenli rasgele sayı üretecini test etme

Diliniz için güvenli rasgele sayı üretecinin gerçekten rastgele olmadığından veya buggy (aralık dışı değerler vb.) Olduğundan emin değilseniz, çıktının ayrıntılı bir istatistiksel analizini birkaç yüz milyonun üzerinde tekrarlamanız gerekir. Her sayının oluşum sıklığı arsa ve eşit olasılık ile ortaya çıkması gerekir. Sonuçlar bir şekilde veya başka bir şekilde çarpıksa, bulgularınızı çerçeve tasarımcılarına bildirmelisiniz. Güvenli rastgele sayı üreteçleri birçok şifreleme algoritması için temel olduğundan, sorunu çözmekle kesinlikle ilgilenecektir.


1

Asla% 100 kesin olamayacaksınız, bu nedenle yapabileceğiniz en iyi şey, sayıların rastlantısal olma ihtimalinin yüksek olması. Bir olasılık seçin - bir hata payı dahilinde, bir milyon numune verildiğinde, x sayısının veya sayı örneğinin x katına çıkacağını söyleyin. Şeyi milyon kere çalıştırın ve sınırın dahilinde olup olmadığına bakın. Neyse ki, bilgisayarlar bu tür işleri yapmayı kolaylaştırıyor.


Ancak bunun gibi birim testler iyi bir uygulama olarak kabul edilir mi? Her zaman bir birim testinin mümkün olduğu kadar basit olması gerektiğini düşündüm: döngüler, dallar veya önlenebilecek başka hiçbir şey yok.
dlras2

4
Birim testleri doğru olmalıdır . Dallanma alırsa, döngüler, özyineleme - bu fiyattır. Tek astarlı birim testleri ile son derece sofistike, en iyi duruma getirilmiş sınıfları birim test edemezsiniz. Dijkstra'nın algoritmasını bir sınıfı bir kerede test etmek için kullandım.
K.Steff

3
@ K.Steff, vay. Dijkstra algoritmasının doğru olduğunu doğrulamak için birim testinizi yaptınız mı?
Winston Ewert,

İşin aslı, iyi bir nokta - evet, ama bu sefer 'önemsiz' sınavlarla. Yine de orijinal program için birim testlerdi (A *). Bunun gerçekten iyi bir uygulama olduğunu düşünüyorum - hızlı algoritmaları test etmek, topal (ama doğru) uygulamaları tekrarlar.
K.Steff

1

Bir rastgele sayı kaynağının en azından rastgele görünüme sahip bir şey ürettiğini test etmek için, testin oldukça büyük bir bayt dizisi oluşturmasını, bunları geçici bir dosyaya yazmasını ve sonra Fourmilab'ın ent aracına göndermesini istiyorum. Ent-t (tiz) anahtarı verin, böylece ayrıştırılması kolay CSV oluşturur. Ardından "iyi" olduklarını görmek için çeşitli sayıları kontrol edin.

Hangi sayıların iyi olduğuna karar vermek için, testinizi kalibre etmek için bilinen bir rastgelelik kaynağını kullanın . İyi bir rasgele sayı kümesi verildiğinde, test hemen hemen her zaman geçmelidir. Gerçekten rastgele bir dizinin bile rastgele olmayan görünen bir diziyi üretme olasılığı olduğundan, geçmesi kesin olan bir test yapamazsınız. Siz sadece rastgele bir dizinin testin başarısız olmasına neden olma ihtimalini düşüren eşikleri seçersiniz. Rastgelelik eğlenceli değil mi?

Not: Bir PRNG'nin "rastgele" bir sekans oluşturduğunu gösteren bir test yazamazsınız. Yalnızca geçerse, PRNG tarafından oluşturulan dizinin "rastgele" olma olasılığını gösteren bir test yazabilirsiniz. Rastgelelik sevinci hoş geldiniz!


1

Durum 1: Bir karışıklığın test edilmesi:

Bir Dizi [0, 1, 2, 3, 4, 5] düşünün, karıştırın, ne yanlış gidebilir? Her zamanki şeyler: a) hiç karıştırmaz, b) 1-5 karıştırır, 0 olmaz, 0-4 karıştırır, 5 olmaz, karıştırılır ve her zaman aynı düzen oluşturulur, ...

Hepsini yakalamak için bir test:

100 kez karıştırıp, değerleri her yuvaya ekleyin. Her bir yuvanın toplamı birbirine göre olmalıdır. Ort / Stddev hesaplanabilir. (5 + 0) /2=2.5, 100 * 2.5 = 25. Beklenen değer, örneğin 25 civarındadır.

Değerler aralık dışındaysa, yanlış bir negatif alma ihtimaliniz küçüktür. Bu şansın ne kadar büyük olduğunu hesaplayabilirsiniz. Testi tekrarla. Elbette - testin art arda 2 kez başarısız olması gibi küçük bir şans var. Ancak, birim testi başarısız olursa kaynağını otomatik olarak silen bir rutinin yok, değil mi? Tekrar çalıştır!

Arka arkaya 3 kez başarısız olabilir? Belki şansınızı piyangoda denemelisiniz.

Durum 2: Bir zar atın

Zar atma sorusu aynı soru. 6000 kez zar at.

for (i in 0 to 6000) 
    ++slot [Random.nextInt (6)];
return (slot.max - slot.min) < threshold;
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.