2010-05-27 18 views
22

Dostların ünitenin nasıl test edildiğini merak ediyorum ve "beklenen" koleksiyonun "gerçek" koleksiyonla aynı/benzer olduğunu ileri sürün (sipariş önemli değil). Ünite testinin en iyi yolu Koleksiyon?

Bu iddiayı gerçekleştirmek için, benim basit assert API yazdı: -

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

Eh, işe yarıyor. Integers ya da Strings demetini iddia edersem oldukça basit. Örneğin, örneğin Hazırda Bekletme alanlarının bir koleksiyonunu iddia etmeye çalışıyorum, oldukça acı verici olabilir. Collection.containsAll (..), denetimi gerçekleştirmek için eşittir (..) değerine dayanır, ancak yalnızca iş anahtarlarını kontrol etmek için Hazırda Bekletmelerimdeki (..) eşitlikleri her zaman geçersiz kılar. Hazırda bekletme sitesi) ve bu alanın tüm alanları değil. Tabii ki, sadece iş anahtarlarına karşı kontrol etmek anlamlıdır, ancak sadece iş anahtarlarının (örneğin, yeni veri girişi kaydı) değil, tüm alanların doğru olduğundan emin olmak istiyorum. Yani, bu durumda, ben domain.equals (..) ile uğraşmak ve neredeyse koleksiyon.containsAll (..) güvenmek yerine sadece birim test amaçları için bazı karşılaştırıcıları uygulamak gerekir gibi görünüyor.

Burada kullanabileceğim bazı test kütüphaneleri var mı? Koleksiyonunuzu nasıl test ediyorsunuz?

Teşekkürler.

cevap

8

Eşit yöntem tüm alanları işaretlemiyorsa, Unitils http://unitils.org/ReflectionAssert sınıfını kullanabilirsiniz.

ReflectionAssert.assertReflectionEquals(expectedCollection,actualCollection) 

çağrılması alana göre her yansıtıcı eleman alanını karşılaştırır (ve bu sadece koleksiyonları için geçerli değildir, herhangi bir nesne için çalışır).

+0

Bu, koleksiyonumun onaylanması için iyi bir yol gibi görünüyor. A, B'yi uzatırsa, hem A hem de B alanlarını dikkate alacağımı varsayalım mı, doğru mu? API belgelerinde bulamıyorum, ancak sanırım bunu test edebilirim. Sadece A alanından değil, B alanlarından gelenleri belirtmek için bir kural belirtmenin bir yolu var mı? – limc

+0

tamam, bu oldukça müthiş ... sadece belgeleri okuyun ve yansıma öğesi kullanmam göründüğünden bu yana ReflectionAssert.assertLenientEquals (..) kullanıyorum. Çok teşekkürler. – limc

+0

@limc. Rica ederim. Alt sınıf alanlarını kontrol etmenin bir yolu olduğundan emin değilim (mümkün olabilir, hiç denemedim). –

16

Kullandığınız JUnit sürümünün tam sürümden emin değilim, ancak son sürümlerinde bir Hamcrest Matcher argüman olarak kullanılan bir assertThat yöntemi var. Birleştirilebilirler, böylece bir koleksiyon hakkında karmaşık iddialar oluşturabilirsiniz. Eğer bir koleksiyon A koleksiyon B her eleman içerdiği iddia etmek istiyorsa

Örneğin, yazabilirsiniz:

ilk test sadece her nesne üzerinde equalTo() eşleyici kullanır
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()))) 
    } 
} 

(hangi edecek eşittir uygulamanıza delege). Bu yeterince güçlü değilse, her elemanı karşılaştırmak için alıcıları ve ayarlayıcıları kullanacak olan ikinci davayı kullanabilirsiniz. Son olarak, kendi maççılarınızı bile yazabilirsiniz. Hamcrest paketi, alanla eşleşmesi için bir eşleştirici ile birlikte gelmiyor (eşleştirme özelliklerinin aksine), bir FieldMatcher yazmak (ve gerçekten de iyi bir egzersiz) için önemsiz.

Kibritçiler ilk başta biraz garip, ancak yeni Eşleştiriciler yapma örneklerini izlerseniz, eşleştiriciyi döndüren statik bir yöntem varsa, import static s bir demet yapabilir ve kodunuz temel olarak İngilizce bir cümle gibi okunur (" Her ikisinin de b'ye sahip olduğu ve b ") ile aynı boyuta sahip olduğunu iddia ediniz. Bu şeylerle oldukça etkileyici bir DSL oluşturabilir ve test kodunuzu çok daha şık hale getirebilirsiniz.

+0

Bilgi için teşekkürler. Sanırım bunların gerçekten var olduğunu fark etmedim. :) Ama benim şu anki senaryomda benim için çalışacağını düşünmüyorum. Belgeleri okudum ve equalTo() Object.equals kullanarak nesne eşitliğini test ediyor gibi görünüyor ve benim durumumda, eğer mümkünse, benim eşitliğimle (..) etrafta dolaşmak istemiyorum. Ama bu yararlı referansı gelecekte kullanmak için akılda tutacağım. – limc

+0

Doğru, equalTo() eşleyicisi, equals() kullanır, ancak SamePropertyValuesAs, iki JavaBeans'in tüm alıcıları ve ayarlayıcılarıyla eşleşir. Ancak, özel alanları veya bir şeyi eşleştirmeniz gerekirse, bu rotayı izlerseniz kendi başınızı döndürmeniz gerekir. – jasonmp85

+5

@ jasonmp85 Bu kod hala sizin için çalışıyor mu? (org.hamcrest.Matcher >> alıyorum >) CombinableMatcher içinde (org.hamcrest.Matcher >>) 'Hamcrest 1.2 – ArtB

0

jasonmp85's answer'un son bölümünü olduğu gibi çalışamıyorum. Kullandığım ithalatı da dahil ettim çünkü bazı cenaze kavanozları kolaylık sağlamak için eski hamcrest malzemelerini içeriyor. Bu benim için çalışıyor, ama assil loop kesinlikle hasItems(..) jason cevabında yazıldığı gibi çalışmış gibi güzel değil.

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

Döngüler için ayrı ayrı gerek yok, bu daha özlü: 'için (son Foo beklenenFoo: b) {assertThat (a, hasItem (yeni SamePropertyValuesAs (beklenenFoo))); } ' –

1

Eğer koleksiyonu oluşturmak değil eğer Başka bir seçenek: Nesnelerin sırasını kontrol etmek istemiyorsanız

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"))))); 
} 

kullanın containsInAnyOrder.

P.S. Eklenen uyarılardan kaçınmak için herhangi bir yardım gerçekten takdir edilecektir.