多表场景下如何用H2数据库、模拟JDBC Template编写DAO类JUnit测试用例
多DAO多表场景下H2 + JdbcTemplate单元测试适配方案
你可以通过抽取公共逻辑、分层管理SQL脚本的方式,把单DAO的测试逻辑复用至全量DAO测试场景,具体实现步骤如下:
1. 抽取公共基础测试父类
把H2数据源初始化、公共脚本加载、DAO依赖注入的通用逻辑全部抽到父类中,避免每个DAO测试重复编写相同代码:
// 基础DAO测试父类 public class BaseDaoTest { protected DataSource dataSource; protected JdbcTemplate jdbcTemplate; // 每个测试方法执行前初始化H2内存库 @Before public void initH2DataSource() { EmbeddedDatabaseBuilder dbBuilder = new EmbeddedDatabaseBuilder() .setType(EmbeddedDatabaseType.H2) // 配置H2兼容模式,适配生产库语法(比如MySQL/PostgreSQL) .setName("testdb;MODE=MySQL;DATABASE_TO_LOWER=TRUE;CASE_INSENSITIVE_IDENTIFIERS=TRUE") // 加载全量公共建表脚本(比如全局字典表、配置表等所有DAO都依赖的表) .addScript("classpath:jdbc/common-schema.sql"); // 可根据测试场景动态添加额外脚本,子类可以覆写这个方法加自己需要的表脚本 addCustomScripts(dbBuilder); dataSource = dbBuilder.build(); jdbcTemplate = new JdbcTemplate(dataSource); } // 子类扩展点:添加当前DAO测试需要的业务表脚本、测试数据脚本 protected void addCustomScripts(EmbeddedDatabaseBuilder dbBuilder) { } // 每个测试方法执行后销毁H2库,保证测试数据隔离 @After public void destroyH2DataSource() { if (dataSource instanceof EmbeddedDatabase) { ((EmbeddedDatabase) dataSource).shutdown(); } } }
2. 分层管理SQL脚本
如果表数量较多,不要把所有建表语句都放在同一个schema.sql里,按业务模块拆分脚本:
- 公共脚本:存放在
classpath:jdbc/common/目录下,放所有DAO都依赖的公共表结构、基础数据 - 业务模块脚本:按业务域拆分,比如
classpath:jdbc/user/放用户相关表脚本,classpath:jdbc/order/放订单相关表脚本,每个模块下分开存放schema.sql(建表语句)和test-data.sql(测试数据) - 按需加载:测试对应DAO的时候,只加载依赖的模块脚本,不需要全量加载所有表,大幅提升测试启动速度
3. 单DAO测试实现
各个DAO的测试类只要继承基础父类,按需加载对应业务脚本即可,不需要再重复写H2初始化逻辑:
public class EmployeeDAOTest extends BaseDaoTest { private EmployeeDAO employeeDAO; // 扩展父类方法,加载员工模块的表结构和测试数据 @Override protected void addCustomScripts(EmbeddedDatabaseBuilder dbBuilder) { dbBuilder.addScript("classpath:jdbc/employee/schema.sql") .addScript("classpath:jdbc/employee/test-data.sql"); } @Before public void initDao() { employeeDAO = new EmployeeDAO(); // 如果DAO依赖DataSource直接注入 employeeDAO.setDataSource(dataSource); // 如果DAO依赖JdbcTemplate就注入JdbcTemplate // employeeDAO.setJdbcTemplate(jdbcTemplate); } @Test public void whenQueryEmployeeCount_thenReturnCorrectValue() { assertEquals(4, employeeDAO.getCountOfEmployees()); } // 其他DAO方法测试直接写即可 }
4. 大量表场景的优化方案
如果表数量超过百级,全量加载脚本速度慢,可以做以下优化:
- 按需加载依赖表:测试某个DAO时只加载它操作的相关表,不要加载无关业务域的表
- 复用H2实例:把H2的初始化逻辑从
@Before改成@BeforeClass,整个测试类只初始化一次数据源,测试方法之间通过清理数据脚本保证隔离,不用每次重建库 - 开启H2缓存:在H2连接参数中添加
;CACHE_SIZE=10000,提升SQL执行速度
注意事项
- 如果生产库用了特殊语法(比如MySQL的
ON DUPLICATE KEY UPDATE、PostgreSQL的COPY语法),需要提前测试H2的兼容情况,少量不兼容的SQL可以单独写H2适配版本的脚本 - 可以配合
@Transactional注解实现测试数据自动回滚,不用手动编写清理数据的脚本
内容的提问来源于stack exchange,提问作者user16718299
相关产品推荐
相关产品推荐

