如何JUnittesting两个List <E>包含相同的顺序相同的元素?
上下文
我正在为MyObject
类写一个简单的JUnittesting。
一个MyObject
可以从一个静态工厂方法创build,该方法使用String的可变参数。
MyObject.ofComponents("Uno", "Dos", "Tres");
在MyObject
存在的任何时候,客户端可以通过.getComponents()
方法,以List <E>的forms检查它创build的参数。
myObject.ofComponents(); // -> List<String>: { "Uno", "Dos", "Tres" }
换句话说,一个MyObject
都会记住并显示使其存在的参数列表。 关于这个合同的更多细节:
-
getComponents
的顺序将与用于创build对象的顺序相同 - 重复后续的string组件是允许和保留的顺序
-
null
上的行为是未定义的(其他代码保证没有null
到工厂) - 在对象实例化之后,没有办法改变组件的列表
我正在写一个简单的testing,从String列表创build一个MyObject
,并检查它是否可以通过.getComponents()
返回相同的列表。 我立即做了这个,但是这应该是在一个现实的代码path上发生的 。
码
这里我的尝试:
List<String> argumentComponents = Lists.newArrayList("One", "Two", "Three"); List<String> returnedComponents = MyObject.ofComponents( argumentComponents.toArray(new String[argumentComponents.size()])) .getComponents(); assertTrue(Iterables.elementsEqual(argumentComponents, returnedComponents));
题
- 是谷歌Guava
Iterables.elementsEqual()
最好的方式,只要我在我的构buildpath库,比较这两个列表? 这是我一直在痛苦的事情; 我应该使用这个帮助器方法,通过一个可重用的<E> ..检查大小,然后迭代运行.equals()
..或互联网searchbuild议的任何其他方法? 比较unit testing列表的规范方法是什么?
我希望获得可选的见解
- 方法testing是否合理devise? 我不是JUnit的专家!
-
.toArray()
是将List <E>转换为E的可变参数的最佳方式吗?
我更喜欢使用Hamcrest,因为如果出现故障,它会提供更好的输出
Assert.assertThat(listUnderTest, IsIterableContainingInOrder.contains(expectedList.toArray()));
而不是报告
expected true, got false
它会报告
expected List containing "1, 2, 3, ..." got list containing "4, 6, 2, ..."
IsIterableContainingInOrder.contain
Hamcrest
根据Javadoc:
为Iterables创build一个匹配器,匹配的时候,一次遍历被检查的Iterable会生成一系列的项目,每个项目在逻辑上等于指定项目中的相应项目。 对于正匹配,被检查的迭代必须与指定项目的数量相同
因此, listUnderTest
必须具有相同数量的元素,每个元素必须按顺序匹配期望的值。
为什么不简单地使用List#equals
?
assertEquals(argumentComponents, imapPathComponents);
List#equals
合同List#equals
:
如果两个列表按照相同的顺序包含相同的元素,则它们被定义为相等的。
所以你的List实现上的equals()方法应该做元素比较
assertEquals(argumentComponents, returnedComponents);
是很容易的。
org.junit.Assert.assertEquals()
和org.junit.Assert.assertArrayEquals()
完成这个工作。
为了避免下一个问题:如果你想忽略所有的元素来设置,然后比较: Assert.assertEquals(new HashSet<String>(one), new HashSet<String>(two))
但是,如果你只是想忽略重复,但保留顺序包装与LinkedHashSet
列表。
又一个小费。 技巧Assert.assertEquals(new HashSet<String>(one), new HashSet<String>(two))
工作正常,直到比较失败。 在这种情况下,它向您显示错误消息,可能会令您感到困惑,因为集合中的顺序几乎不可预测(至less对于复杂对象)。 所以,我发现的技巧是用有序集而不是HashSet
来包装集合。 您可以使用TreeSet
与自定义比较器。
对于优秀的代码可读性, Fest Assertions对断言列表有很好的支持
所以在这种情况下,就像这样:
Assertions.assertThat(returnedComponents).containsExactly("One", "Two", "Three");
或者把预期的列表做成一个数组,但我更喜欢上面的方法,因为它更清晰。
Assertions.assertThat(returnedComponents).containsExactly(argumentComponents.toArray());
- 我的答案是否
Iterables.elementsEqual
是最好的select:
Iterables.elementsEqual
足以比较2 List
。
Iterables.elementsEqual
用于更一般的场景,它接受更一般的types: Iterable
。 也就是说,你甚至可以将List
与Set
进行比较。 (通过迭代次序,这很重要)
当然ArrayList
和LinkedList
定义相当不错,你可以直接调用equals。 而当你使用一个不明确定义的列表时, Iterables.elementsEqual
是最好的select。 有一件事应该注意: Iterables.elementsEqual
不接受null
-
将List转换为数组:
Iterables.toArray
是easer。 -
对于unit testing,我build议在testing用例中添加空列表 。