使用JMock为简单的spring JDBC DAO编写单元测试

时间:2012-04-12 16:55:49

标签: java spring-jdbc jmock

我正在为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上。它也不起作用,抱怨“并非所有参数都有明确的匹配器:要么所有参数都必须由匹配器指定,要么所有参数都必须由值指定,你不能混合使用匹配器和值”

3 个答案:

答案 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方法得到了太多的重载。