簡體   English   中英

單元測試集合的最佳方式?

[英]Best way to unit test Collection?

我只是想知道人們如何測試並斷言“預期”集合與“實際”集合相同/相似(順序並不重要)。

為了執行這個斷言,我編寫了我的簡單斷言API: -

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

嗯,它的工作原理。 如果我斷言只是一堆整數或字符串,這很簡單。 例如,如果我試圖斷言Hibernate域的集合,那也可能會非常痛苦。 collection.containsAll(..)依賴於equals(..)來執行檢查,但我總是覆蓋我的Hibernate域中的equals(..)以僅檢查業務鍵(這是最好的做法,在Hibernate網站)而不是該域的所有字段。 當然,檢查業務鍵是有意義的,但有時我真的想確保所有字段都正確,而不僅僅是業務鍵(例如,新的數據輸入記錄)。 因此,在這種情況下,我無法使用domain.equals(..)並且幾乎看起來我需要實現一些比較器,僅用於單元測試目的,而不是依賴於collection.containsAll(..)。

我可以在這里使用一些測試庫嗎? 你如何測試你的收藏?

謝謝。

我不確定你正在使用什么版本的JUnit,但是最近有一個使用Hamcrest Matcher作為參數的assertThat方法。 它們是可組合的,因此您可以構建關於集合的復雜斷言。

例如,如果你想斷言集合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()匹配器(它將委托給你的equals實現)。 如果這還不夠強大,你可以使用第二種情況,它將使用getter和setter來比較每個元素。 最后,您甚至可以編寫自己的匹配器。 Hamcrest包沒有匹配字段匹配(而不是匹配bean屬性),但編寫FieldMatcher很簡單(確實是一個很好的練習)。

Matchers一開始有點奇怪,但是如果你按照他們的例子來制作新的Matchers有一個返回匹配器的靜態方法你可以做一堆import static s並且你的代碼基本上讀起來像一個英語句子(“斷言a兩者都有b中的項目,並且與b“)具有相同的大小。 您可以使用這些東西構建一個非常令人印象深刻的DSL,並使您的測試代碼更加優雅。

如果equals方法不檢查所有字段,則可以使用Unitils http://unitils.org/ ReflectionAssert類。 調用

ReflectionAssert.assertReflectionEquals(expectedCollection,actualCollection)

將逐個字段地反復比較每個元素(這不僅適用於集合,它將適用於任何對象)。

如果您尚未構建集合,則另一個選項:

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

PS任何有助於避免被禁止的警告的幫助將非常感激。

我無法得到jasonmp85的最后一部分答案 我包括了我使用的進口,因為為方便起見,一些junit罐包括舊的hamcrest東西。 這對我hasItems(..) ,但是assert循環肯定不像hasItems(..)那樣好,就像jason的回答一樣。

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

...

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM