有 Java 编程相关的问题?

你可以在下面搜索框中键入要查询的问题!

java在Mockito中安装后重置模拟的正确替代方案是什么?

我不熟悉单元测试,并尝试学习正确的风格。我喜欢设置我正在测试的对象,这样我就可以像在使用它一样测试它,而不是只测试一个新构建的对象。我无法测试从一个空的对象中移除东西,因为很多对象在构建时都是空的

以下面的例子为例,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 for reset甚至没有时间告诉您该方法的功能,因为它忙于告诉您不应该使用它。通常,我会简单地接受这个建议,通过删除我的setup方法并调整我的测试来避免reset

  @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方法的文档说明:

Instead of reset() please consider writing simple, small and focused test methods over lengthy, over-specified tests.

我尊重Mockito是为了鼓励单元测试中的良好风格而设计的,我想从中学习,但我很难理清它想要传达给我什么样的信息。当我把reset从我的测试中去掉时,我的测试变得复杂,更长,更不集中,,所以显然我做错了

正确的做法是什么样子的


共 (2) 个答案

  1. # 1 楼答案

    移除reset。移除verifyNoMoreInteractions。问题解决了。你的测试更简单、更短、更集中

  2. # 2 楼答案

    Mockito 2.1添加了一个clearInvocations方法,可以这样使用:

    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));
        clearInvocations(listener);
      }
    
      @Test public void addFirst() {
        list.add(0, -1);
        verify(listener, only()).listEdited(list, 0, 1, Collections.<Integer>emptyList());
      }
    
      @Test void addAtEnd() {
        list.add(9);
        verify(listener, only()).listEdited(list, 3, 4, Collections.<Integer>emptyList());
      }
    
      @Test void removeMiddle() {
        list.remove(Integer.valueOf(2));
        verify(listener, only()).listEdited(list, 1, 1, Collections.singletonList(2));
      }
    }
    

    请注意clearInvocationsjavadoc还声明:

    Try to avoid this method at all costs. Only clear invocations if you are unable to efficiently test your program.