是否可以模拟并忽略属性

时间:2018-12-10 13:56:53

标签: unit-testing spring-boot mocking mockito

我正在更改身份策略,并且使用的是在将实体写入数据库之前生成的ID。由于我们模拟某些服务调用的方式,此更改导致我们的某些测试失败。

TimeLog timeLog = buildTimeLog('123456', mockEmployeeId);
TimeLog mockTimeLog = buildTimeLog('123456', mockEmployeeId);
when(this.timeLogService.save(mockTimeLog)).thenReturn(timeLog);

当测试调用Controller时,Controller中绑定的实体将获得与预期的模拟不同的ID,因为该实体会生成该ID。以前,数据库会生成ID,因此模拟程序可以正常工作。

是否有一种方法可以告诉Mockito忽略期望中的某个属性?这样可以解决问题,并且测试仍然有效。否则,欢迎使用其他方法。

1 个答案:

答案 0 :(得分:1)

您不能告诉Mockito忽略期望中的属性,因为它使用的是Java的“等于”方法...您可以在TimeLog中定义一个等于ID的equals方法,但我怀疑这样做不会给您带来什么想。另一种方法是,与其尝试告诉嘲笑未验证的内容,不如使用hamcrest匹配器明确定义要验证的内容。定义一个仅与您要验证的字段(即ID以外的所有其他字段)匹配的hamcrest匹配器。像这样:

private class TimeLogMatcher extends TypeSafeMatcher<TimeLog> {
    private final EmployeeId employeeId;

    public TimeLogMatcher(EmployeeId employeeId) {
        this.employeeId = employeeId;
    }

    @Override
    public void describeTo(Description description) {
        description.appendText("TimeLog with employeeId=" + employeeId);
    }

    @Override
    public boolean matchesSafely(TimeLog item) {
        return employeeId.equals(item.getEmployeeId());
    }
}

然后不调用您的“ buildTimeLog”方法正在调用的Mockito Matchers类,例如:

TimeLog timeLog = Matchers.argThat(new TimeLogMatcher(mockEmployeeId));

或者,您也可以始终使用Answer对象:

when(this.timeLogService.save(any(TimeLog.class)).thenAnswer(new Answer<TimeLog> {
    public TimeLog answer(InvocationOnMock invocation) throws Throwable {
        TimeLog receivedTimeLog = invocation.getArgumentAt(0, TimeLog.class);
        assertThat(receivedTimeLog.getEmployeeId(), equalTo(mockEmployeeId));
        return timeLog;
    }
});

这一切有意义吗?