我想将合适的对象传递给verify方法,而不仅仅是任何()。
有办法吗?
我不能只接受并复制Lambda方法并将结果传递给验证。这不起作用,因为Lambdas无法直接测试。
我的单元测试显然甚至没有接近测试任何东西:
@Test
public void testRunTrigger() {
campaignTrigger.updateCampaignStatus();
verify(jdbcTemplate).update(any(PreparedStatementCreator.class));
assertEquals("UPDATE campaign SET state = 'FINISHED' WHERE state IN ('PAUSED','CREATED','RUNNING') AND campaign_end < ? ", campaignTrigger.UPDATE_CAMPAIGN_SQL);
}
这是我正在测试的课程:
@Component
@Slf4j
public class CampaignTrigger {
final String UPDATE_CAMPAIGN_SQL = String.format("UPDATE campaign SET state = '%s' " +
" WHERE state IN (%s) AND campaign_end < ? ", FINISHED,
Stream.of(PAUSED, CREATED, RUNNING)
.map(CampaignState::name)
.collect(Collectors.joining("','", "'", "'")));
@Autowired
private JdbcTemplate jdbcTemplate;
@Scheduled(cron = "${lotto.triggers.campaign}")
@Timed
void updateCampaignStatus() {
jdbcTemplate.update(con -> {
PreparedStatement callableStatement = con.prepareStatement(UPDATE_CAMPAIGN_SQL);
callableStatement.setTimestamp(1, Timestamp.valueOf(LocalDateTime.now()));
log.debug("Updating campaigns statuses.");
return callableStatement;
});
}
任何建议,或理论知识,这不是这样做的方式,我将非常感激。
答案 0 :(得分:4)
您不应该模拟您无法控制的代码。只模拟你测试的代码,因为在模拟时你假设你知道(即你定义)模拟类是如何工作的。
在这里,你不知道jdbcTemplate
是如何工作的,以及用一些lambda调用它实际上是否符合你的想法。
使用您无法控制的代码测试代码是集成测试的重点。即你应该测试你的CampaignTrigger
和一个真实的数据库(或内存数据库),而不是嘲笑jdbcTemplate
。
答案 1 :(得分:3)
您可以通过捕获用于该通话的对象来试试运气,请参阅here。这允许编写如下代码:
ArgumentCaptor<Person> argument = ArgumentCaptor.forClass(Person.class);
verify(mock).doSomething(argument.capture());
assertEquals("John", argument.getValue().getName());
授予您完整访问传递给方法调用的对象的权限!请注意,mockito最近推出了一个@Captor注释,使事情更容易使用。
编辑;鉴于@Morfic的评论:他所说的是绝对合理的。
这个答案给出了“立竿见影”的提示,说明如何解决这个具体问题。
超越:合理的方法总是始终将“被测单元”切成薄片......尽可能小!
您的班级/方法应该只承担一项责任;然后确保可以使用最简单的方法测试实现。
所以:如果问题是:“我应该使用参数捕获器还是我应该更好地修改我的生产代码” - 然后重新编写您的生产代码。