在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)));
这对于仅返回少量值的测试来说非常适合。但如果测试返回更多值,这绝对不是最好的方法。
我也试过以下代码。要编译的代码需要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
列表却不容易。
答案 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]。
但对于初学者来说,这可能有助于你获得更好的想法。
更新:如果您无法修改列表,则可以随时复制并对其进行排序。