如何对我收到正确的PreparedStatement进行单元测试?

时间:2017-03-28 09:43:58

标签: java unit-testing junit mocking mockito

我想将合适的对象传递给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;
    });
}

任何建议,或理论知识,这不是这样做的方式,我将非常感激。

2 个答案:

答案 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的评论:他所说的是绝对合理的。

这个答案给出了“立竿见影”的提示,说明如何解决这个具体问题。

超越:合理的方法总是始终将“被测单元”切成薄片......尽可能小!

您的班级/方法应该只承担一项责任;然后确保可以使用最简单的方法测试实现。

所以:如果问题是:“我应该使用参数捕获器还是我应该更好地修改我的生产代码” - 然后重新编写您的生产代码。