我是单元测试的新手,并试图学习正确的风格。我喜欢设置我正在测试的对象,这样我就可以像在使用它一样测试它,而不是只测试一个新构建的对象。我无法测试从空对象中删除东西,因为构造时有很多对象。
以下面的例子为例,其中 ObservedList 正在被测试,ListListener 是一个被模拟的必要类。
public final class ObservedListTest {
private ListListener<Integer> listener;
private ObservedList<Integer> list;
@BeforeMethod public void setup() {
listener = mock(ListListener.class);
list = new ObservedList<Integer>(listener);
list.addAll(Arrays.asList(1,2,3));
reset(listener);
}
@Test public void addFirst() {
list.add(0, -1);
verify(listener).listEdited(list, 0, 1, Collections.<Integer>emptyList());
verifyNoMoreInteractions(listener);
}
@Test void addAtEnd() {
list.add(9);
verify(listener).listEdited(list, 3, 4, Collections.<Integer>emptyList());
verifyNoMoreInteractions(listener);
}
@Test void removeMiddle() {
list.remove(Integer.valueOf(2));
verify(listener).listEdited(list, 1, 1, Collections.singletonList(2));
verifyNoMoreInteractions(listener);
}
}
作为一个新手,这对我来说似乎很有效,但我知道这是不好的做法,因为它使用了这种reset
方法。我打电话reset
是因为我不希望实际测试由于设置中发生的交互而混淆。
javadoc forreset
甚至没有告诉您该方法的作用,因为它正忙于告诉您不应该使用它。通常我会简单地接受这个建议并reset
通过删除我的setup
方法并调整我的测试看起来更像这样来避免:
@Test void removeMiddle() {
listener = mock(ListListener.class);
list = new ObservedList<Integer>(listener);
list.addAll(Arrays.asList(1,2,3));
list.remove(Integer.valueOf(2));
InOrder inOrder = inOrder(listener);
inOrder.verify(listener).listEdited(list, 0, 3,
Collections.<Integer>emptyList());
inOrder.verify(listener).listEdited(list, 1, 1,
Collections.singletonList(2));
verifyNoMoreInteractions(listener);
}
这对我来说似乎也很有效。问题是该reset
方法的文档说:
请考虑在冗长、过度指定的测试中编写简单、小型和集中的测试方法,而不是 reset()。
我尊重 Mockito 旨在鼓励单元测试中的良好风格,我想从中学习,但我很难理清它试图向我发送的信息。当我从我的测试中删除reset
时,我的测试变得复杂、冗长且注意力不集中,所以很明显我做错了。
做对了是什么样的?