[英]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.