模拟对象单元测试有问题

Having trouble with a mock object unit test

我正在玩弄模拟对象,但在设置检查列表是否正确排序的单元测试时遇到了问题。这样做的想法是我在模拟一个时钟,但仅仅使用 times() 方法是行不通的。该列表应按升序排列,但只需 returns 获取第一个索引,无论最后设置什么值。

作为参考,这里是一个工作模拟测试,测试时钟设置在午夜:

@Test
public void shouldSetAtMidnight() {
    expect(mock.instant()).andReturn(Instant.from(this.midnight));

    expect(mock.getZone()).andReturn(this.timeZone);

    replay(mock);

    this.st.setDesiredValue(72);
    SetPoint[] sched = this.st.getSchedule();

    verify(mock);

    assertEquals(LocalTime.MIDNIGHT, sched[0].getScheduledTime());
}

在这里,设置所需的值很重要,因为它会向数组添加一个 SetPoint(setDesiredValue 创建一个具有 int 和 LocalTime 的 SetPoint)。这是我遇到困难的地方:

@Test
public void shouldOrderTwoSetPointsAddedOutOfOrder() {
    expect(mock.instant()).andReturn(Instant.from(this.midnight)).times(2);

    expect(mock.getZone()).andReturn(this.timeZone).times(2);

    replay(mock);

    this.st.setDesiredValue(73);
    this.st.setDesiredValue(71);
    SetPoint[] schedule = this.st.getSchedule();

    verify(mock);

    assertEquals(71, schedule[0].getTemp());
}

setDesiredValue 应该将 int 值与 LocalTime 相关联,在本例中应该是午夜。然后它将具有这些特征的 SetPoint 添加到列表中,并调用 Collection 的 sort() 方法将它们从低到高排序。现在,我假设我的问题是尽管为两个期望调用 times(2),但我将两个值与完全相同的时间相关联,但我最近才开始使用模拟对象并且只是不了解他们知道从这里去哪里。 运行 本次测试 returns 73 而不是 71.

你的假设是正确的。当您说 .andReturn(Instant.from(this.midnight)).times(2) 时,传递给 .andReturn 的确切值会重复两次。

你可以做 .andReturn(Instant.from(this.midnight)).andReturn(Instant.from(this.midnight)),这会给你两个瞬间。但作为一般规则,这对于单元测试来说是非常糟糕的形式。 Instant.from(this.midnight) 来自测试之外,因此您无法预测调用此函数两次会产生相同的值还是不同的值,从而使测试具有不确定性。可以进行集成测试,但不可以进行单元测试,因为您将在其中使用模拟。最好使用实数,例如 .andReturn(Instant.fromEpochSecond(10)).andReturn(Instant.fromEpochSecond(15)).

您没有提供有关 st 的全部详细信息以及您认为测试不应该 return 73 而不是 71 的任何原因。