如何在JUnit

时间:2016-03-15 15:15:10

标签: java junit hamcrest

在JUnit 4测试中,我有一个方法getValues(),它返回一个我想与参考列表进行比较的List<Double>对象。到目前为止,我发现的最佳解决方案是使用org.hamcrest.collection.IsArray.hasItemsorg.hamcrest.Matchers.closeTo,如下所示:

assertThat(getValues(), hasItems(closeTo(0.2, EPSILON), closeTo(0.3, EPSILON)));

这对于仅返回少量值的测试来说非常适合。但如果测试返回更多值,这绝对不是最好的方法。

我也试过以下代码。要编译的代码需要Matcher之前的hasItems向下转换:

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:     预期:(包含&lt; [<&lt; 1.0E-6&gt;内的数值&lt; 0.2&gt;,&lt; 1.0E-6&gt;&lt; 0.3&gt;内的数值>&gt;)的集合)          得到:&lt; [0.2,0.30000000000000004]&gt;

  

有没有更好的方法来比较两个大型双打名单?这里的困难是需要数值容差来验证getValues()的结果是否等于我的参考列表。对于任何对象列表,这种比较似乎都很容易,但对于Double列表却不容易。

7 个答案:

答案 0 :(得分:7)

我认为这里正确的解决方案是自定义Matcher。基本上像IsIterableContainingInOrder这样的东西只适用于双打,并支持错误边距。

答案 1 :(得分:5)

如果您愿意从List<Double>转换为double[]assertArrayEquals允许指定错误容差:

assertArrayEquals(new double[] {1, 2}, new double[] {1.01, 2.09}, 1E-1);

Java 8中,从列表到数组的转换相对干净(请参阅related question)。例如:

double[] toArray(List<Double> list) {
    return list.stream().mapToDouble(Number::doubleValue).toArray();
}

然后断言声明可以如下:

assertArrayEquals(toArray(refList), toArray(getValues()), 1E-9);

P.S。 只需将签名更改为toArray即可使Number与任何double[] toArray(List<? extends Number> list)类型一起使用。

答案 2 :(得分:0)

没有hasItems方法将匹配器列表作为参数。但您可以使用the one with varargs

首先将匹配器列表转换为数组

@SuppressWarnings("unchecked")
private Matcher<Double>[] toDoubleMatcherArray(List<Matcher<Double>> doubleMatchers) {
    return doubleMatchers.toArray(new Matcher[0]);
}

并像这样称呼它

assertThat(getValues(), hasItems(toDoubleMatcherArray(doubleMatcherList)));

答案 3 :(得分:0)

您需要使用contains()而不是hasItems()

hasItems()的回复转换为Matcher隐藏了类型错误。您的代码实际上是在检查getValues()的结果是List是否是您创建的Matcher,而不是根据结果评估Matcher getValues()

这是因为hasItems()没有像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()的错误重载。

答案 4 :(得分:0)

如果您愿意将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);
  }
}

答案 5 :(得分:-2)

我不相信没人提到它。如果您有预期的列表,

  • 希望实际列表与预期列表的顺序相同,然后使用

    assertEquals(expected,actual);

  • 希望列表无论顺序如何都是相同的 assertTrue(expected.containsAll(actual) && actual.containsAll(expected));

答案 6 :(得分:-3)

如果这两个列表有不同的长度,那么说它们是不同的。如果它们具有相同的长度,则对列表进行排序。排序后,比较相同索引的元素。

这可以更详细地讨论是否应该将列表A中的每个元素与列表B中的相应元素进行比较,例如:比较A [i]与B [i-d],... B [i],...,B [i + d]。

但对于初学者来说,这可能有助于你获得更好的想法。

更新:如果您无法修改列表,则可以随时复制并对其进行排序。