我正在为spring jdbc dao编写一个单元测试。测试方法是:
public long getALong() {
return simpleJdbcTemplate.queryForObject("sql query here", new RowMapper<Long>() {
public Long mapRow(ResultSet resultSet, int i) throws SQLException {
return resultSet.getLong("a_long");
}
});
}
以下是测试中的内容:
public void testGetALong() throws Exception {
final Long result = 1000L;
context.checking(new Expectations() {{
oneOf(simpleJdbcTemplate).queryForObject("sql_query", new RowMapper<Long>() {
public Long mapRow(ResultSet resultSet, int i) throws SQLException {
return resultSet.getLong("a_long");
}
});
will(returnValue(result));
}});
Long seq = dao.getALong();
context.assertIsSatisfied();
assertEquals(seq, result);
}
当然,测试不起作用(否则,我不会在这里问这个问题)。问题是测试中的rowmapper与DAO中的rowmapper不同。所以没有达到预期。
我尝试将with
放在sql查询周围,将with(any(RowMapper.class))
放在rowmapper上。它也不起作用,抱怨“并非所有参数都有明确的匹配器:要么所有参数都必须由匹配器指定,要么所有参数都必须由值指定,你不能混合使用匹配器和值”
答案 0 :(得分:2)
也为查询字符串提供匹配器,例如
oneOf(simpleJdbcTemplate).queryForObject(
with( equal("sql_query") ),
with( any(RowMapper.class) )
);
答案 1 :(得分:2)
我想你可能会在这里遗漏几点。您的第一次尝试再现了模拟中目标代码的行为。你真的想测试什么?
对于这种测试,我更喜欢编写一个关注真实数据库的测试。多年前我试过嘲笑JDBC并对此感到后悔。在这种代码中通常失败的是与数据库的关系,而不是java代码本身。
这实际上是一个查询(它不会改变对象之外的世界状态),所以我倾向于使用allowing()
子句而不是oneOf()
。它是相同的潜在机制,但更好地表达了意图。
最后,不要直接调用context.assertIsSatisfied()
,而应考虑使用
@RunWith(JMock.class)
在测试的顶部。
答案 2 :(得分:1)
我在最后添加with(any(Object.class))
解决了这个问题。
oneOf(jdbcTemplate).queryForObject(with(equal("sql_query")), with(any(RowMapper.class)), with(any(Object.class)));
我认为jmock在找到正确的调用方法时遇到了麻烦,因为queryForObject方法得到了太多的重载。