簡體   English   中英

如何在JUnit中比較兩個double列表

[英]How to compare two lists of double in JUnit

在JUnit 4測試中,我有一個方法getValues() ,它返回一個List<Double>對象,我想與參考列表進行比較。 到目前為止,我發現的最佳解決方案是使用org.hamcrest.collection.IsArray.hasItemsorg.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個MatcherList ,它不會根據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.

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