我有一些API我尝试彻底 集成 测试 - 我正在尝试在测试环境中运行的远程服务(不是运行测试的同一个框,测试进行真正的服务调用),我不能只使用依赖注入来解决我的所有问题。我们已经对这些类进行了一系列良好的单元测试。
我测试的API是SaveThingy。如果它有效,它会保存一个Thingy,并返回它的id。其中一项检查是,您只能在某些时间保存,只能在工作日保存。如果你在周末打电话给SaveThingy,它会侮辱你,而不是保存一个Thingy。实现类似于以下
ThingyId saveThingy(Thingy thingy) {
if (isWeekend(LocalDate.now().getDayOfWeek())) {
throw new PersonalInsultException("your mother wears army boots");
}
return thingyDao.save(thingy);
}
理想情况下,我希望每次运行集成测试时都会测试这两种情况,而不需要等待。在某些代码中,我希望每次都运行类似于以下的测试。
@Test
public void saveThingy_validThingyOnWeekday_savesThingy() {
ThingyId id = serviceUnderTest.saveThingy(THINGY);
assertThat(serviceUnderTest.getThingyById(id)).isEqualTo(THINGY);
}
@Test(expected = PersonalInsultException.class)
public void saveThingy_validThingyOnWeekend_receivePersonalInsult() {
serviceUnderTest.saveThing(THINGY);
}
是否有任何标准方法可以完全测试此类API?我考虑了一些选项(下面),但想获得更多意见。
答案 0 :(得分:2)
我想在你的ThingyService
课程中,你有一个公众
或受保护的isWeekend
方法。可能是这样的:
public boolean isWeekend(DayOfWeek dayOfWeek) {
return dayOfWeek == DayOfWeek.SATURDAY || dayOfWeek == DayOfWeek.SUNDAY;
}
在ThingyServiceTest
中,您可以使用模拟的ThingyService
方法创建两个专门的isWeekend
个实例。
在您的测试用例中,您可以使用以下任一方法:
// service with weekday behavior
private ThingyService serviceUnderTest_weekday = new ThingyService() {
@Override
public boolean isWeekend(DayOfWeek dayOfWeek) {
return false;
}
};
// service with weekend behavior
private ThingyService serviceUnderTest_weekend = new ThingyService() {
@Override
public boolean isWeekend(DayOfWeek dayOfWeek) {
return true;
}
};
@Test
public void saveThingy_validThingyOnWeekday_savesThingy() {
ThingyId id = serviceUnderTest_weekday.saveThingy(THINGY);
assertThat(serviceUnderTest_weekday.getThingyById(id)).isEqualTo(THINGY);
}
@Test(expected = PersonalInsultException.class)
public void saveThingy_validThingyOnWeekend_receivePersonalInsult() {
serviceUnderTest_weekend.saveThing(THINGY);
}
答案 1 :(得分:1)
您正在尝试使用白盒测试要求进行黑盒测试:这根本不可能。坚持白盒测试并在本地模拟你的DateProvider。也许不是你想听到的,但是你会浪费那么多时间,否则你会试图调整星星以产生你想要的输出。
另一方面,如果您真的想这样做,请在Docker容器中运行您的应用程序并更改系统时钟,然后在测试之间将其拆除。
或者打开一个单独的端点,允许通过您的服务指定当前时间,并在测试时仅部署此端点。或者有一个配置界面负责确定当前时间的来源,以及何时部署到测试环境,相应地配置应用程序。
答案 2 :(得分:1)
不要使用LocalDate.now()
或Instant.now()
或Whatever.now()
或传递long
个时间戳,请考虑在您的类中添加java.time.Clock
字段,并添加初始化参数构造函数或提供setter。
Clock.instant()
基本上是Instant.now()
,您可以将该广告转换为任何其他时态类。
在制作中,您将使用Clock.systemUTC()
作为该字段的值。
在某些测试中,您可以使用Clock.fixed()
,在所有测试中,您可以模拟测试所需的方式。
这种方法主要适用于单元测试。您仍然可以在集成环境中注入自定义Clock
实现,这样整个应用程序就会认为当前时间是您需要的。