Rastgele olaylara dayanan kodu kapsayacak şekilde test senaryolarını nasıl tasarlayabilirim?


15

Örneğin, kod 0-10 arasında rastgele bir int oluşturuyor ve her sonuç için farklı bir dal alırsa, böyle bir kodda% 100 ifade kapsamını garanti etmek için bir test paketi nasıl tasarlanabilir?

Java'da kod şöyle olabilir:

int i = new Random().nextInt(10);
switch(i)
{
    //11 case statements
}

Yanıtlar:


22

David'in cevabını genişleterek, tamamen katılıyorum, Rastgele için bir ambalaj oluşturmalısınız. Benzer bir soruda daha önce aynı cevabı yazdım, işte bunun bir "Cliff'in not versiyonu".

Yapmanız gereken ilk olarak sarmalayıcıyı bir arayüz (veya soyut sınıf) olarak oluşturmaktır:

public interface IRandomWrapper {
    int getInt();
}

Ve bunun somut sınıfı şöyle görünecektir:

public RandomWrapper implements IRandomWrapper {

    private Random random;

    public RandomWrapper() {
        random = new Random();
    }

    public int getInt() {
        return random.nextInt(10);
    }

}

Diyelim ki sınıfınız şöyledir:

class MyClass {

    public void doSomething() {
        int i=new Random().nextInt(10)
        switch(i)
        {
            //11 case statements
        }
    }

}

IRandomWrapper'ı doğru şekilde kullanmak için sınıfınızı üye olarak alacak şekilde değiştirmeniz gerekir (yapıcı veya ayarlayıcı aracılığıyla):

public class MyClass {

    private IRandomWrapper random = new RandomWrapper(); // default implementation

    public setRandomWrapper(IRandomWrapper random) {
        this.random = random;
    }

    public void doSomething() {
        int i = random.getInt();
        switch(i)
        {
            //11 case statements
        }
    }

}

Artık, sarmalayıcıyla alay ederek sınıfınızın davranışını sarmalayıcı ile test edebilirsiniz. Bunu alaycı bir çerçeveyle yapabilirsiniz, ancak bunu kendiniz de yapmak kolaydır:

public class MockedRandomWrapper implements IRandomWrapper {

   private int theInt;    

   public MockedRandomWrapper(int theInt) {
       this.theInt = theInt;
   }

   public int getInt() { 
       return theInt;
   }

}

Sınıfınız bir şeye benzeyen bir şey beklediğinden IRandomWrapper, alay edileni testinizdeki davranışı zorlamak için kullanabilirsiniz. JUnit testlerine bazı örnekler:

@Test
public void testFirstSwitchStatement() {
    MyClass mc = new MyClass();
    IRandomWrapper random = new MockedRandomWrapper(0);
    mc.setRandomWrapper(random);

    mc.doSomething();

    // verify the behaviour for when random spits out zero
}

@Test
public void testFirstSwitchStatement() {
    MyClass mc = new MyClass();
    IRandomWrapper random = new MockedRandomWrapper(1);
    mc.setRandomWrapper(random);

    mc.doSomething();

    // verify the behaviour for when random spits out one
}

Bu yardımcı olur umarım.


3
Buna tamamen katılıyorum. Bir olayın rastgele doğasını kaldırarak rastgele bir olayı test edersiniz. Aynı teori zaman damgaları için de kullanılabilir
Richard

3
Not: Nesneye ihtiyacı olan başka bir nesneyi vermesi için bu tehdide, onları örneklemesine izin vermek yerine, Bağımlılık Enjeksiyonu
Clement Herreman

23

Rastgele nesil kodunu bir sınıfa veya yönteme sarabilir (sınamalı) ve ardından sınamalar sırasında istediğiniz değeri ayarlamak için taklit / geçersiz kılabilirsiniz, böylece sınamalarınız tahmin edilebilir.


5

Belirli bir aralık (0-10) ve belirli bir ayrıntı düzeyi (tam sayılar) var. Test yaparken rastgele sayılarla test yapmazsınız. Her vakayı sırayla vuran bir döngü içinde test edersiniz. Rasgele sayıyı, yalnızca alt işlevi sınamanıza izin veren case deyimini içeren bir alt işleve geçirmenizi öneririm.


önerdiğimden çok daha iyi (çünkü daha basit), benim oylarımı transfer edebilseydim :)
David

Aslında ikisini de yapmalısınız. Her dalı ayrı ayrı test etmek için sahte bir RandomObject ile test edin ve gerçek RandomObject ile tekrar tekrar test edin. Birincisi bir birim test, ikincisi daha çok bir entegrasyon testi gibidir.
sleske

3

Rastgele sınıfı taklit etmek için PowerMock kütüphanesini kullanabilir ve beklenen değeri döndürmek için nextInt () yöntemini saplayabilirsiniz. İstemiyorsanız orijinal kodunuzu değiştirmenize gerek yoktur.

PowerMockito kullanıyorum ve sizinkine benzer bir yöntemi denedim. JUnit testi yayınladığınız kod için şöyle görünmelidir:

@RunWith(PowerMockRunner.class)
@PrepareForTest( { Random.class, ClassUsingRandom.class } ) // Don't forget to prepare the Random class! :)

public void ClassUsingRandomTest() {

    ClassUsingRandom cur;
    Random mockedRandom;

    @Before
    public void setUp() throws Exception {

        mockedRandom = PowerMockito.mock(Random.class);

        // Replaces the construction of the Random instance in your code with the mock.
        PowerMockito.whenNew(Random.class).withNoArguments().thenReturn(mockedRandom);

        cur = new ClassUsingRandom();
    }

    @Test
    public void testSwitchAtZero() {

        PowerMockito.doReturn(0).when(mockedRandom).nextInt(10);

        cur.doSomething();

        // Verify behaviour at case 0
     }

    @Test
    public void testSwitchAtOne() {

        PowerMockito.doReturn(1).when(mockedRandom).nextInt(10);

        cur.doSomething();

        // Verify behaviour at case 1
     }

    (...)

Anahtarınıza daha fazla vaka eklemek istemeniz durumunda, herhangi bir parametre almak için nextInt (int) çağrısını da saplayabilirsiniz:

PowerMockito.doReturn(0).when(mockedRandom).nextInt(Mockito.anyInt());

Güzel, değil mi? :)


2

QuickCheck kullanın ! Son zamanlarda bununla oynamaya başladım ve inanılmaz. Çoğu harika fikir gibi Haskell'den geliyor ama temel fikir, test öncesi konserve test vakalarını vermek yerine rastgele sayı üretecinizin sizin için bunları oluşturmasına izin vermenizdir. Bu şekilde, xUnit'te muhtemelen karşılaşacağınız 4-6 durum yerine, bilgisayarın yüzlerce veya binlerce girişi denemesini ve hangilerinin belirlediğiniz kurallara uymadığını görebilirsiniz.

Ayrıca QuickCheck, başarısız bir durum bulduğunda, başarısız olan en basit durumu bulabilmesi için basitleştirmeye çalışacaktır. (Ve elbette başarısız bir durum bulduğunuzda, bunu bir xUnit testine de oluşturabilirsiniz)

Java'nın en az iki sürümü olduğu anlaşılıyor, bu nedenle bu bölüm bir sorun olmamalı.

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.