[英]Unit Test : check if a particular Comparable has been called
考虑这种方法,我想为此编写一个单元测试。
public void update(List toUpdate) {
//...
Collections.sort(toUpdate, new SpecificComparator());
//...
}
我想确保我们使用SpecificComparator实现对给定列表进行排序。 无论如何要这样做?
我当时正在考虑使用工厂来检索SpecificComparator实现,以便我可以通过Mockito验证我们正在调用工厂,但是这不能确保在给定该比较器的情况下列表是有序的,我们可以想象有人在调用该工厂。方法中的工厂,但不使用它来排序列表...
或者,我也可以验证toUpdate
列表对象的排序,在我的单元测试中使用相同的比较器对另一个列表进行排序,并检查它们的排序方式是否相同?
如此之多的答案,都包含一个“真相”,却缺少其他。 伤心。
因此:您绝对应该避免使用模拟在排序调用上测试比较器。 相反,您要测试两个方面:
assertThat(actualList, is(expectedList));
长话短说:比较器本身就是一个单元。 您开始测试该东西; 与所有极端情况,什么不是。 然后,确保应该对列表进行排序的方法的确与排序后的列表一起返回。
而且,如果您的代码仍然需要考虑模拟,那么可能会将您的设计改进为易于测试(而不是难以测试)。
想法是, 如果使用了特定的比较器,则已对列表进行排序。 这很重要,因为比较器的行为不应更改,如果更改,则应写入新要求,这意味着必须更改用于测试的列表。 但是,在大多数情况下,您不应该过于频繁地更改单个比较器的行为。 因此,您应该创建已经使用比较器进行排序的列表,然后可以调用以下方法
public boolean unitTestComparator(List sorted, Comparator comp)
{
List shuffled = new List(sorted);
Collections.shuffle(shuffled);
return sorted.equals(Collections.sort(shuffled, comp));
}
现在,您可以对各种列表使用多种测试,以对不同比较器进行所有边缘测试。 所有这一切的关键在于,您知道使用比较器后的列表应该是什么样的,唯一麻烦的部分是找到每个比较器的所有边缘情况。 您还可以在该方法上运行一个for循环,以对其进行多次测试,因为您为该方法提供了正确的列表格式。 它所做的就是随机洗牌。
请注意,这是随机测试,您还可以向该方法添加另一个参数,该参数可以是您想要的方式随机排列的列表,以查找特定的边缘情况。
我会说这不是要做的合理的事情。
单元测试仅应在其公共接口上测试类,并且由于比较器是隐藏的实现细节,因此如何获得排序顺序与单元测试无关。
这意味着,如果某天实现发生更改,以通过其他方式达到相同的排序顺序,则测试将继续通过-事情就是这样。
因此,您应该测试输出是否按期望的顺序排序,但是您不应断言有关该方法专用的对象的任何信息。
当然,如果使Comparator
成为类的API的一部分,那将是另一回事:
public class Updater {
private final Comparator sortComparator;
public Updater(Comparator sortComparator) {
this.sortComparator = sortComparator;
}
public void update(List toUpdate) {
//...
Collections.sort(toUpdate, sortComparator);
//...
}
}
...然后将模拟Comparator
传递给构造函数,并断言它已被使用是合适的-因为现在调用者很感兴趣,传递给它的Comparator
是正在使用的,因此应该测试的东西。
您在上面提到的我将其称为“交叉测试”,但我认为这是不必要的,如果您真的想实现它,我会给您,让您多加考虑。 测试使用不同的比较器两次更新一个列表,并断言您期望得到结果。
public class CrossingTest {
@Test
public void sortWithSpecificComparator() throws Throwable {
List<Integer> list = asList(0, 1, 2);
List<Integer> reversedList = asList(2, 1, 0);
Comparator<Integer> originalOrder = (a, b) -> a < b ? -1 : 1;
assertThat(update(list, with(originalOrder)), equalTo(list));
assertThat(update(list, with(originalOrder.reversed()))
, equalTo(reversedList));
}
private List<Integer> update(List<Integer> input, Comparator comparator) {
List<Integer> list = new ArrayList<>(input);
SUT it = new SUT(comparator);
it.update(list);
return list;
}
private Comparator with(Comparator comparator) { return comparator; }
}
class SUT {
private Comparator comparator;
public SUT(Comparator comparator) {
this.comparator = comparator;
}
public void update(List toUpdate) {
Collections.sort(toUpdate, comparator);
}
}
尽管可以使用以下方法模拟新对象:
SpecificComparator comparator = Mockito.mock(SpecificComparator.class);
Mockito.whenNew(SpecificComparator.class).thenReturn(comparator);
最好的方法始终是在调用方法之后检查元素的顺序,而不是检查何时/如何使用比较器。 您可以使用List的 equals
方法来做到这一点,它就是这样说的:
比较指定对象与此列表是否相等。 当且仅当指定对象也是一个列表,并且两个列表具有相同的大小,并且两个列表中所有对应的元素对相等时,才返回true。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.