[英]How to compare two lists of double in JUnit
在JUnit 4測試中,我有一個方法getValues()
,它返回一個List<Double>
對象,我想與參考列表進行比較。 到目前為止,我發現的最佳解決方案是使用org.hamcrest.collection.IsArray.hasItems
和org.hamcrest.Matchers.closeTo
像這樣:
assertThat(getValues(), hasItems(closeTo(0.2, EPSILON), closeTo(0.3, EPSILON)));
這適用於僅返回少量值的測試。 但是如果測試返回更多值,這絕對不是最好的方法。
我也嘗試了以下代碼。 在編譯代碼時,需要在hasItems
之前向下轉換為Matcher
:
List<Matcher<Double>> doubleMatcherList = new ArrayList<Matcher<Double>>();
doubleMatcherList.add(closeTo(0.2, EPSILON));
doubleMatcherList.add(closeTo(0.3, EPSILON));
assertThat(getValues(), (Matcher) hasItems(doubleMatcherList));
比較失敗,我不明白為什么:
java.lang.AssertionError:Expected :(一個包含<[數字值<1.0E-6> <0.2>的數字,<1.0> -0> <0.3>的數值>]>的集合得到:<[ 0.2,0.30000000000000004]>
是否有更好的方法來比較兩個大型雙打名單? 這里的困難是需要數值容差來驗證getValues()
的結果是否等於我的引用列表。 對於任何對象列表,這種比較似乎都很容易,但對於Double
列表則不然。
我認為這里正確的解決方案是自定義匹配器 。 基本上類似於IsIterableContainingInOrder ,它只適用於雙打並支持錯誤邊距。
如果您願意從List<Double>
轉換為double[]
, assertArrayEquals允許指定錯誤容差:
assertArrayEquals(new double[] {1, 2}, new double[] {1.01, 2.09}, 1E-1);
在Java 8中 ,從列表到數組的轉換相對簡潔(參見相關問題 )。 例如:
double[] toArray(List<Double> list) {
return list.stream().mapToDouble(Number::doubleValue).toArray();
}
然后斷言聲明可以如下:
assertArrayEquals(toArray(refList), toArray(getValues()), 1E-9);
通過將簽名更改為double[] toArray(List<? extends Number> list)
可以使ps toArray
可以使用任何Number
類型。
沒有hasItems
方法將匹配器列表作為參數。 但你可以使用varargs 。
首先將匹配器列表轉換為數組
@SuppressWarnings("unchecked")
private Matcher<Double>[] toDoubleMatcherArray(List<Matcher<Double>> doubleMatchers) {
return doubleMatchers.toArray(new Matcher[0]);
}
並稱之為這樣
assertThat(getValues(), hasItems(toDoubleMatcherArray(doubleMatcherList)));
您需要使用contains()
而不是hasItems()
。
將hasItems()
的返回hasItems()
為Matcher
隱藏了類型錯誤。 您的代碼實際上是在檢查getValues()
的結果是否是一個包含您創建的2個Matcher
的List
,它不會根據getValues()
的結果來評估這些Matcher
。
這是因為hasItems()
沒有過載List<Matcher<? super T>>
List<Matcher<? super T>>
喜歡contains()
的確如此。
這樣做你想要的,而無需經歷自定義Matcher
的麻煩:
List<Matcher<? super Double>> doubleMatcherList = new ArrayList<>();
doubleMatcherList.add(closeTo(0.2, EPSILON));
doubleMatcherList.add(closeTo(0.3, EPSILON));
assertThat(getValues(), contains(doubleMatcherList));
請注意doubleMatcherList
的參數化類型。 如果它只是List<Matcher<Double>>
則選擇contains()
的錯誤重載。
如果您願意從Hamcrest更改為AssertJ斷言,這里是java 8中的解決方案。
import static org.assertj.core.api.Assertions.assertThat;
import java.util.Arrays;
import java.util.Comparator;
import java.util.List;
import org.junit.Test;
// import java.util.function.Function;
public class DoubleComparatorTest {
// private static final Double DELTA = 1E-4;
// private static final Function<Double, Comparator<Double>> DOUBLE_COMPARATOR_WITH_DELTA =
// (delta) -> (o1, o2) -> (o1 - o2 < delta) ? 0 : o1.compareTo(o2);
private Comparator<Double> COMPARATOR = (o1, o2) -> (o1 - o2 < 0.0001) ? 0 : o1.compareTo(o2);
@Test
public void testScaleCalculationMaxFirstPositive() {
List<Double> expected = Arrays.asList(1.1D, 2.2D, 3.3D);
List<Double> actual = Arrays.asList(1.10001D, 2.2D, 3.30001D);
assertThat(actual)
// .usingElementComparator(DOUBLE_COMPARATOR_WITH_DELTA.apply(DELTA))
.usingElementComparator(COMPARATOR)
.isEqualTo(expected);
}
}
我不相信沒有人提到它。 如果你有預期的列表,和
希望實際列表與預期列表的順序相同然后使用
assertEquals(expected,actual);
希望列表無論順序如何都是相同的,然后執行assertTrue(expected.containsAll(actual) && actual.containsAll(expected));
如果這兩個列表有不同的長度,那么說它們是不同的。 如果它們具有相同的長度,則對列表進行排序。 對它們進行排序后,比較同一索引處的元素。
這可以更詳細地討論是否應該將列表A中的每個元素與列表B中的對應元素進行比較,例如將A [i]與B [id]進行比較,... B [i],...,B [i + d]。
但對於初學者來說,這可能會幫助你獲得更好的想法。
更新:如果您無法修改列表,則可以隨時復制它們並對其進行排序。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.