2010-05-27 20 views
22

मैं सोच रहा हूं कि लोग कैसे यूनिट परीक्षण करते हैं और जोर देते हैं कि "अपेक्षित" संग्रह "वास्तविक" संग्रह के समान/समान है (ऑर्डर महत्वपूर्ण नहीं है)।इकाई परीक्षण संग्रह का सबसे अच्छा तरीका?

इस दावे करने के लिए, मैं अपने सरल ज़ोर एपीआई लिखा है: -

public void assertCollection(Collection<?> expectedCollection, Collection<?> actualCollection) { 
    assertNotNull(expectedCollection); 
    assertNotNull(actualCollection); 
    assertEquals(expectedCollection.size(), actualCollection.size()); 
    assertTrue(expectedCollection.containsAll(actualCollection)); 
    assertTrue(actualCollection.containsAll(expectedCollection)); 
} 

खैर, यह काम करता है। यह बहुत आसान है अगर मैं केवल इंटीजर या स्ट्रिंग्स का गुच्छा लगा रहा हूं। अगर मैं हाइबरनेट डोमेन का संग्रह करने की कोशिश कर रहा हूं, तो यह भी बहुत दर्दनाक हो सकता है, उदाहरण के लिए कहें। संग्रह.containsAll (..) चेक करने के लिए बराबर (..) पर निर्भर करता है, लेकिन मैं हमेशा अपने हाइबरनेट डोमेन में बराबर (..) को ओवरराइड करता हूं ताकि केवल व्यवसाय कुंजी जांच सकें (जो कि सबसे अच्छा अभ्यास है हाइबरनेट वेबसाइट) और उस डोमेन के सभी फ़ील्ड नहीं। निश्चित रूप से, यह केवल व्यवसाय कुंजी के खिलाफ जांच करना समझ में आता है, लेकिन कई बार मैं वास्तव में यह सुनिश्चित करना चाहता हूं कि सभी फ़ील्ड सही हैं, न केवल व्यवसाय कुंजी (उदाहरण के लिए, नया डेटा एंट्री रिकॉर्ड)। तो, इस मामले में, मैं domain.equals (..) के साथ गड़बड़ नहीं कर सकता और ऐसा लगता है कि मुझे कुछ compators को केवल compution.contains पर निर्भर करने के बजाय इकाई परीक्षण उद्देश्यों के लिए लागू करने की आवश्यकता है। (सभी)।

क्या कुछ परीक्षण पुस्तकालय मैं यहां लाभ उठा सकते हैं? आप अपने संग्रह का परीक्षण कैसे करते हैं?

धन्यवाद।

उत्तर

8

यदि बराबर विधि सभी फ़ील्ड की जांच नहीं करती है, तो आप यूनिटिल http://unitils.org/ReflectionAssert कक्षा का उपयोग कर सकते हैं। कॉलिंग

ReflectionAssert.assertReflectionEquals(expectedCollection,actualCollection) 

क्षेत्र द्वारा प्रत्येक तत्व संजीदगी से क्षेत्र की तुलना करेंगे (और यह सिर्फ संग्रहों के लिए लागू नहीं होता है, यह किसी भी वस्तु के लिए काम करेंगे)।

+0

यह मेरे संग्रह के दावे के लिए एक अच्छा तरीका प्रतीत होता है। यदि ए बी बढ़ाता है, तो मुझे लगता है कि यह ए और बी दोनों के खेतों का विवरण लेगा, क्या यह सही है? मैं इसे एपीआई दस्तावेज में नहीं ढूंढ सकता, लेकिन मुझे लगता है कि मैं इसका परीक्षण कर सकता हूं। क्या ए और बी से केवल फ़ील्ड पर जोर देने के लिए नियम निर्दिष्ट करने का कोई तरीका है? – limc

+0

ठीक है, यह बहुत बढ़िया है ... बस प्रलेखन को पढ़ें, और ऐसा लगता है कि मुझे ReflectionAssert.assertLenientEquals (..) का उपयोग करना चाहिए क्योंकि यह आइटम ऑर्डर का खाता नहीं लेता है। बहुत धन्यवाद। – limc

+0

@limc। आपका स्वागत है। मुझे बस सबक्लास फ़ील्ड की जांच करने के तरीके पर यकीन नहीं है (यह संभव हो सकता है, मैंने कभी कोशिश नहीं की है)। –

16

मुझे यकीन नहीं है कि आप जिस जुनीट का उपयोग कर रहे हैं, लेकिन हाल के लोगों में assertThat विधि है जो एक तर्क के रूप में Hamcrest Matcher लेता है। वे composable हैं ताकि आप एक संग्रह के बारे में जटिल दावे का निर्माण कर सकते हैं।

उदाहरण के लिए, यदि आप का दावा करने की है कि एक संग्रह A संग्रह B में हर तत्व निहित चाहता था, आप लिख सकते हैं:

import static org.junit.Assert.*; 
import static org.junit.matchers.JUnitMatchers.*; 
import static org.hamcrest.core.IsCollectionContaining.*; 
import static org.hamcrest.collection.IsCollectionWithSize.*; 
import org.hamcrest.beans.SamePropertyValuesAs; 

public class CollectionTests { 

    /* 
    * Tests that a contains every element in b (using the equals() 
    * method of each element) and that a has the same size as b. 
    */ 
    @Test 
    public void test() { 
     Collection<Foo> a = doSomething(); 
     Collection<Foo> b = expectedAnswer; 

     assertThat(a, both(hasItems(b)).and(hasSize(b.size()))); 
    } 

    /* 
    * Tests that a contains every element in b (using introspection 
    * to compare bean properties) and that a has the same size as b. 
    */ 
    @Test 
    public void testBeans() { 
     Collection<Foo> a = doSomething(); 
     Collection<Foo> b = expectedAnswer; 
     Collection<Matcher<Foo>> bBeanMatchers = 
      new LinkedList<Matcher<Foo>>(); 

     // create a matcher that checks for the property values of each Foo 
     for(Foo foo: B) 
      bBeanMatchers.add(new SamePropertyValuesAs(foo)); 

     assertThat(a, both(hasItems(bBeanMatchers)).and(hasSize(b.size()))) 
    } 
} 

पहले टेस्ट बस हर वस्तु पर equalTo() मिलान का उपयोग करता है (जो होगा आपके बराबर कार्यान्वयन के लिए प्रतिनिधि)। यदि यह पर्याप्त मजबूत नहीं है, तो आप दूसरे मामले का उपयोग कर सकते हैं, जो प्रत्येक तत्व की तुलना करने के लिए गेटर्स और सेटर्स का उपयोग करेगा। अंत में, आप अपने खुद के मैचर्स भी लिख सकते हैं। Hamcrest पैकेज फ़ील्ड से मिलान करने के लिए एक matcher के साथ नहीं आता है (मिलान बीन गुणों के विपरीत), लेकिन फील्डमैचर लिखना मुश्किल है (और वास्तव में एक अच्छा अभ्यास है)।

मैचर्स पहले थोड़ा अजीब हैं, लेकिन यदि आप नए मैचर्स बनाने के उनके उदाहरण का पालन करते हैं तो एक स्थिर विधि है जो मैचर लौटाती है, आप import static एस का एक गुच्छा कर सकते हैं और आपका कोड मूल रूप से अंग्रेजी वाक्य की तरह पढ़ता है (" जोर देकर कहते हैं कि दोनों में बी में आइटम हैं और बी के समान आकार है ")। आप इन चीजों के साथ एक सुंदर प्रभावशाली डीएसएल बना सकते हैं और अपना टेस्ट कोड बहुत अधिक सुरुचिपूर्ण बना सकते हैं।

+0

जानकारी के लिए धन्यवाद। मुझे लगता है कि मैंने कभी यह महसूस नहीं किया कि ये वास्तव में मौजूद हैं। :) लेकिन मुझे नहीं लगता कि यह मेरे वर्तमान परिदृश्य में मेरे लिए काम करेगा। मैं सिर्फ प्रलेखन को पढ़ता हूं, और ऐसा लगता है जैसे ox.oals का उपयोग करके बराबर() परीक्षण ऑब्जेक्ट समानता का परीक्षण करता है, और मेरे मामले में, यदि संभव हो तो मैं अपने बराबर (..) के साथ फ़ुटज़ नहीं करना चाहता। लेकिन भविष्य में उपयोग के लिए मैं इस उपयोगी संदर्भ को ध्यान में रखूंगा। – limc

+0

दाएं, बराबर() matcher बराबर() का उपयोग करता है, लेकिन समानPropertyValuesAs सभी JavaBeans के सभी गेटर्स और सेटर्स से मेल खाता है। हालांकि, अगर आपको निजी फ़ील्ड या कुछ से मेल खाना पड़ेगा, तो आपको इस मार्ग पर जाने के लिए अपना खुद का रोल करना होगा। – jasonmp85

+5

@ jasonmp85 क्या यह कोड अभी भी आपके लिए काम करता है? मैं हो रही है 'और (org.hamcrest.Matcher >> >) कॉम्बिनेबलमैटर में से (org.hamcrest.Matcher >>) बढ़ाता है Hamcrest 1.2 – ArtB

0

मुझे काम करने के लिए jasonmp85's answer का अंतिम भाग नहीं मिला। मैंने आयात किए गए आयातों को शामिल किया क्योंकि कुछ जूनिट जारों में सुविधा के लिए पुरानी हामक्रिस्ट सामग्री शामिल है। यह मेरे लिए काम करता है, लेकिन जोरदार लूप निश्चित रूप से उतना अच्छा नहीं है जितना hasItems(..) जेसन के उत्तर में लिखा गया है।

import org.hamcrest.Matcher; 
import org.hamcrest.beans.SamePropertyValuesAs; 
import org.hamcrest.collection.IsCollectionWithSize; 

import static org.hamcrest.CoreMatchers.hasItem; 
import static org.hamcrest.MatcherAssert.assertThat; 

... 

/* 
* Tests that a contains every element in b (using introspection 
* to compare bean properties) and that a has the same size as b. 
*/ 
@Test 
public void testBeans() { 
    Collection<Foo> a = doSomething(); 
    Collection<Foo> b = expectedAnswer; 
    Collection<Matcher<Foo>> bBeanMatchers = new LinkedList<Matcher<Foo>>(); 

    // create a matcher that checks for the property values of each Foo 
    for(Foo foo: B) 
     bBeanMatchers.add(new SamePropertyValuesAs(foo)); 

    // check that each matcher matches something in the list 
    for (Matcher<Foo> mf : bBeanMatchers) 
     assertThat(a, hasItem(mf)); 

    // check that list sizes match 
    assertThat(a, IsCollectionWithSize.hasSize(b.size())); 
} 

... 
+0

छोरों के लिए अलग से की आवश्यकता नहीं है, यह अधिक संक्षिप्त है: '(अंतिम फू expectedFoo: ख) के लिए {assertThat (क, hasItem (नई SamePropertyValuesAs (expectedFoo))); } ' –

1

एक अन्य विकल्प यदि आप अपने संग्रह का निर्माण नहीं किया है:

import static org.hamcrest.MatcherAssert.assertThat; 
import static org.hamcrest.Matchers.contains; 
import static org.hamcrest.Matchers.allOf; 
import static org.hamcrest.beans.HasPropertyWithValue.hasProperty; 
import static org.hamcrest.Matchers.is; 

@Test 
@SuppressWarnings("unchecked") 
public void test_returnsList(){ 

    arrange(); 

    List<MyBean> myList = act(); 

    assertThat(myList , contains(allOf(hasProperty("id",   is(7L)), 
             hasProperty("name",  is("testName1")), 
             hasProperty("description", is("testDesc1"))), 
           allOf(hasProperty("id",   is(11L)), 
             hasProperty("name",  is("testName2")), 
             hasProperty("description", is("testDesc2"))))); 
} 

उपयोग containsInAnyOrder अगर आप वस्तुओं के आदेश की जांच नहीं करना चाहती।

पीएस Suppresed चेतावनी से बचने के लिए कोई मदद वास्तव में सराहना की जाएगी।

संबंधित मुद्दे