前面,我们快速搭建了基于H2数据库的本地数据库服务。也提到了h2数据库是一个非常轻量级的内存数据库,sql语法兼容度非常好,且在内存模式下非常易于做单元测试。这里我们就来实践下吧,开干!
profile配置
考虑到我们的配置在不同环境下应该有不一样的设置,比如我们想在本地启动web服务时连的是本地的h2数据库服务,而在本地运行单元测试时连的是基于内存临时启动的一个h2数据库。我们可以通过profile配置不同环境的应用设置,然后在运行时激活相应的profile即可。
现在我们新加一个application-test.yml
配置文件,要注意配置文件命名的格式为application-profile名称.yml
。我们将连接一个基于内存的库,并在数据库创建时运行执行的ddl和dml语句:
spring:
datasource: # 数据源的相关配置
schema:
- classpath:db/schema.sql
data:
- classpath:db/data.sql
url: jdbc:h2:mem:db_juan_mall;DB_CLOSE_DELAY=-1;MODE=MySQL;AUTO_SERVER=FALSE;AUTO_RECONNECT=TRUE;
单元测试调整
修改下原来的测试类,在类的头部加一个激活指定profile的注解:
...
@ActiveProfiles({"test"})
...
public class CategoryMapperTest { ... }
然后我们验证下profile的配置是否生效,可以修改下schema.sql,故意改错,如果有相应报错提示,则说明指定profile的配置确实加载了,如我们所预料的:
同样,我们从控制台输出的日志中也可以看到会按照指定的profile来覆盖配置:
使用内存库来做单元测试的好处是,我们可以为每个单元测试(集成测试)构建一个完全干净的数据库环境,每次跑完后数据就释放了,很好的实现了数据的隔离,并且可以按照需要来初始化数据。
除了在application配置中写死要执行的ddl、dml,还可以手动来加载它们,可以在指定的或者每个单元测试方法运行前执行。
注释掉原来的配置:
改为:
package com.xiaojuan.boot.dao.mapper;
import ...
...
public class CategoryMapperTest {
@Resource
private DataSource dataSource;
...
private ScriptRunner runner;
@PostConstruct
public void initRunner() throws Exception {
runner = new ScriptRunner(dataSource.getConnection());
runner.setAutoCommit(true);
runner.setStopOnError(true);
runner.setLogWriter(null); // 不在控制台输出sql
}
// 每个单元测试方法前执行
@BeforeEach
public void initSql() throws IOException {
runner.runScript(Resources.getResourceAsReader("db/schema.sql"));
runner.runScript(Resources.getResourceAsReader("db/data.sql"));
}
// 单元测试方法省略...
}
这样每个单元测试做到了完全的数据隔离,因为这里我们使用基于内存的h2数据库,建库建表和释放数据库都会非常快。如果初始化的数据量不是特别多的情况下推荐用这种连库和测试方式。