मैं यादृच्छिक घटनाओं के आधार पर कोड को कवर करने के लिए परीक्षण मामलों को कैसे डिजाइन कर सकता हूं?


15

उदाहरण के लिए, यदि कोड 0-10 से एक यादृच्छिक अंतर उत्पन्न करता है, और प्रत्येक परिणाम पर एक अलग शाखा लेता है, तो ऐसे कोड में 100% बयान कवरेज की गारंटी देने के लिए कोई टेस्ट सूट कैसे डिज़ाइन कर सकता है?

जावा में, कोड कुछ इस तरह हो सकता है:

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

जवाबों:


22

डेविड के जवाब का विस्तार करना, जिनसे मैं पूरी तरह सहमत हूं कि आपको रैंडम के लिए एक रैपर बनाना चाहिए। मैंने इसके बारे में पहले भी इसी तरह के प्रश्न में बहुत अधिक उत्तर लिखा था, इसलिए यहां इसका "क्लिफ नोट्स संस्करण" है।

आपको पहले रैपर को एक इंटरफ़ेस (या अमूर्त वर्ग) के रूप में बनाने के लिए क्या करना चाहिए:

public interface IRandomWrapper {
    int getInt();
}

और इसके लिए ठोस वर्ग इस तरह दिखेगा:

public RandomWrapper implements IRandomWrapper {

    private Random random;

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

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

}

कहो कि आपकी कक्षा निम्नलिखित है:

class MyClass {

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

}

IRandomWrapper को सही ढंग से उपयोग करने के लिए आपको इसे एक सदस्य के रूप में लेने के लिए अपनी कक्षा को संशोधित करने की आवश्यकता है (निर्माता या सेटर के माध्यम से):

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
        }
    }

}

अब आप रैपर को मॉक करके अपनी कक्षा के व्यवहार को रैपर के साथ परख सकते हैं। आप इसे एक नकली रूपरेखा के साथ कर सकते हैं, लेकिन यह अपने आप से करना आसान है:

public class MockedRandomWrapper implements IRandomWrapper {

   private int theInt;    

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

   public int getInt() { 
       return theInt;
   }

}

चूँकि आपकी कक्षा को कुछ ऐसी उम्मीद है जो आपके जैसी दिखती है, इसलिए IRandomWrapperअब आप मॉकडाउन का उपयोग करके अपने परीक्षण में व्यवहार को मजबूर कर सकते हैं। यहाँ JUnit परीक्षणों के कुछ उदाहरण दिए गए हैं:

@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
}

उम्मीद है की यह मदद करेगा।


3
इससे पूरी तरह सहमत हैं। आप घटना की यादृच्छिक प्रकृति को हटाकर एक यादृच्छिक घटना का परीक्षण करते हैं। उसी सिद्धांत का उपयोग टाइमस्टैम्प के लिए किया जा सकता है
रिचर्ड

3
नोट: किसी वस्तु को उसकी जरूरत की वस्तु देने के बजाय, उसे बताने के बजाय, उसे यह कहना कि उसे डिपेंडेंसी इंजेक्शन कहा जाता है
क्लेमेंट हेर्रिमैन

23

आप किसी वर्ग या विधि में रैंडम जेनरेशन कोड को लपेट सकते हैं और फिर परीक्षण के दौरान इसे मॉक / ओवरराइड कर सकते हैं ताकि आप जो मूल्य चाहते हैं उसे सेट कर सकें।


5

आपको एक निर्दिष्ट श्रेणी (0-10), और एक निर्दिष्ट ग्रैन्युलैरिटी (संपूर्ण संख्या) मिली है। इसलिए परीक्षण करते समय, आप यादृच्छिक संख्याओं के साथ परीक्षण नहीं करते हैं। आप एक लूप के भीतर परीक्षण करते हैं जो प्रत्येक केस को बदले में हिट करता है। मैं एक उप-फ़ंक्शन में यादृच्छिक संख्या को पास करने की सलाह देता हूं जिसमें केस स्टेटमेंट होता है, जो आपको उप-फ़ंक्शन का परीक्षण करने की अनुमति देता है।


जितना मैंने सुझाव दिया था उससे ज्यादा बेहतर (क्योंकि अधिक सरल), काश मैं अपने upvotes को स्थानांतरित कर सकता :) :)
David

वास्तव में आपको दोनों करना चाहिए। प्रत्येक शाखा का व्यक्तिगत रूप से परीक्षण करने के लिए रैंडम ऑबजेक्ट के साथ टेस्ट करें, और वास्तविक रैंडम ऑबजेक्ट के साथ बार-बार टेस्ट करें। पूर्व एक इकाई परीक्षण है, बाद वाला एक एकीकरण परीक्षण की तरह है।
sleske

3

आप रैंडम क्लास को मॉक करने के लिए पॉवरमॉक लाइब्रेरी का उपयोग कर सकते हैं और अपेक्षित मान वापस करने के लिए इसके अगले आईंट () विधि को स्टब कर सकते हैं। यदि आप नहीं चाहते हैं तो अपना मूल कोड बदलने की आवश्यकता नहीं है।

मैं पॉवरमॉकिटो का उपयोग कर रहा हूं और सिर्फ आपकी तरह एक विधि का परीक्षण किया है। उस कोड के लिए जिसे आपने JUnit परीक्षण पोस्ट किया है, उसे कुछ इस तरह देखना चाहिए:

@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
     }

    (...)

यदि आप अपने स्विच में अधिक मामले जोड़ना चाहते हैं, तो आप किसी भी पैरामीटर को प्राप्त करने के लिए अगली (int) कॉल को भी स्टब कर सकते हैं:

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

सुंदर, है ना? :)


2

QuickCheck का प्रयोग करें ! मैंने हाल ही में इसके साथ खेलना शुरू किया और यह आश्चर्यजनक है। अधिकांश शांत विचारों की तरह यह हास्केल से आता है लेकिन मूल विचार यह है कि अपने परीक्षण पूर्व डिब्बाबंद परीक्षण मामलों को देने के बजाय आप अपने यादृच्छिक संख्या जनरेटर को आपके लिए उन्हें बनाने दें। इस तरह से 4-6 मामलों के बजाय जो आप शायद xUnit के साथ आएंगे, आप कंप्यूटर पर सैकड़ों या हजारों इनपुट आज़मा सकते हैं और देख सकते हैं कि कौन से नियम आपके द्वारा निर्धारित नियमों के अनुरूप नहीं हैं।

साथ ही क्विकचेक तब होगा जब यह एक असफल मामला पाता है इसे सरल बनाने का प्रयास करें ताकि यह सबसे सरल संभव मामला ढूंढ सके जो विफल हो। (और निश्चित रूप से जब आप एक असफल मामला पाते हैं तो आप इसे xUnit परीक्षण में भी बना सकते हैं)

जावा के लिए कम से कम दो संस्करण प्रतीत होते हैं ताकि भाग को कोई समस्या न हो।

हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.