对使用 Spring JDBC 的 DAO 类进行单元测试

Posted

技术标签:

【中文标题】对使用 Spring JDBC 的 DAO 类进行单元测试【英文标题】:Unit testing a DAO class that uses Spring JDBC 【发布时间】:2011-07-21 04:43:10 【问题描述】:

我有几个 DAO 对象用于从数据库中检索信息,我真的想为它们编写一些自动化测试,但我很难弄清楚如何去做。

我正在使用 Spring 的 JdbcTemplate 运行实际查询(通过准备好的语句)并将结果映射到模型对象(通过 RowMapper 类)。

如果我要编写单元测试,我不确定我会/应该如何模拟对象。例如,由于只有读取,我会使用实际的数据库连接,而不是模拟 jdbcTemplate,但我不确定这是否正确。

这是批处理中最简单的 DAO 的(简化)代码:

/**
 * Implementation of the @link BusinessSegmentDAO interface using JDBC.
 */
public class GPLBusinessSegmentDAO implements BusinessSegmentDAO 
    private JdbcTemplate jdbcTemplate;

    private static class BusinessSegmentRowMapper implements RowMapper<BusinessSegment>  
        public BusinessSegment mapRow(ResultSet rs, int arg1) throws SQLException  
            try 
                return new BusinessSegment(rs.getString(...));
             catch (SQLException e) 
                return null;
            
        
    

    private static class GetBusinessSegmentsPreparedStatementCreator 
        implements PreparedStatementCreator 
        private String region, cc, ll;
        private int regionId;

        private GetBusinessSegmentsPreparedStatementCreator(String cc, String ll) 
            this.cc = cc;
            this.ll = ll;
        

        public PreparedStatement createPreparedStatement(Connection connection)
                throws SQLException            
            String sql = "SELECT ...";

            PreparedStatement ps = connection.prepareStatement(sql);
            ps.setString(1, cc);
            ps.setString(2, ll);
            return ps;
        
    

    public GPLBusinessSegmentDAO(DataSource dataSource) 
        jdbcTemplate = new JdbcTemplate(dataSource);
    

    public Collection<BusinessSegment> getBusinessSegments(String cc, String ll) 
        return jdbcTemplate.query(
                new GetBusinessSegmentsPreparedStatementCreator(cc, ll), 
                new BusinessSegmentRowMapper());
    


任何想法都将不胜感激。

谢谢!

【问题讨论】:

你可以看看Acolyte,一个对JDBC持久性进行单元测试的框架,真正的隔离 【参考方案1】:

请查看以下链接:

    Testing SQL queries with Spring and DbUnit MockObjects or DBUnit for testing Code using JdbcTemplate

希望对您有所帮助。

编辑:

这里是GitHub version of RowMapperTests,方便参考。

【讨论】:

SpringSource 已移至 github,您可以找到 RowMapperTests here。编辑:我已经用新链接更新了答案。【参考方案2】:

我建议您打破对JdbcTemplate 类的依赖,并改用JdbcOperations 接口,例如

public class GPLBusinessSegmentDAO implements BusinessSegmentDAO 
    private final JdbcOperations jdbc;

    public GPLBusinessSegmentDAO(DataSource dataSource) 
        this(new JdbcTemplate(dataSource));
    

    public GPLBusinessSegmentDAO(JdbcOperations jdbc) 
        this.jdbc = jdbc;
    

    // ... DAO methods here

您的单元测试可以调用第二个构造函数,传入一个模拟 JdbcOperations 对象。由于所有 DB 操作都是通过 jdbc 对象执行的,因此您可以轻松地模拟它。

您的实时代码可以像以前一样调用第一个构造函数。

【讨论】:

【参考方案3】:

要为此编写真正的单元测试,您不会接触到真正的数据库。 但是,您可能会发现将真实的 DataSource 传递到底层数据库并测试 getBusinessSegments() 方法返回 0、1 和许多结果,具体取决于您传入的 cc 和 ll 值。

另一个值得研究的选项是传入一个嵌入式Java DB 的数据源,该数据源是在 setUp/@Before 方法中使用您的架构初始化的。我猜您真正想要测试的是 SELECT... 查询是否正确映射到架构,因此这样的测试将捕获运行时出现的任何错误,例如架构更改。

【讨论】:

以上是关于对使用 Spring JDBC 的 DAO 类进行单元测试的主要内容,如果未能解决你的问题,请参考以下文章

Spring的JDBC模板

spring对dao层的支持

采用DTO和DAO对JDBC程序进行进一步优化

Spring之DAO一

Spring 对DAO 的支持

[刘阳Java]_Spring对Dao的支持_第10讲