SpringBoot使用H2内存数据库单元测试的代码示例
一、背景
单元测试是提高代码质量和保证代码正确性的重要保证。
DAO的单元测试有常见的两种方案。
【1】使用H2这类内存数据库进行单元测试。
【2】使用MySQL数据库,测试后回滚。
两种方案各有利弊,个人倾向于前者。
网上有很多示例,都是很多案例没有给出可运行的项目源码,搭建过程中会遇到很多坑,本文文末会给出可运行源码,方便大家改造学习。
二、利弊对比
下面是自己的个人观点,仅供参考。
2.1 使用H2这类内存数据库进行单元测试
官网地址:http://www.h2database.com/html/main.html
github地址:https://github.com/h2database/h2database
使用H2内存数据库来单元测试的优势在于
- h2更快速,且支持JDBC API。
- 支持内嵌和服务器模式;是一种内存的数据库
- 支持浏览器控制台
- jar包比较小
另外
- 如果使用公共的开发数据库,服务器如果回收再测试就需要继续安装建表和插入数据。
- 如果每个人都本地测试,为了测试都要安装MySQL或Oracle等数据库并手动执行建表和插入。
当然也有一些劣势,虽然可以支持多种数据库模式,但是特殊的语句可能会不支持。
个人更倾向于推荐这种内存数据库进行DAO层单测的方式。
2.2 使用MySQL测试后回滚
使用MySQL测试后回滚是常见的一种方式,最大的问题如果是自己本地测试,其他人如果想测试需要再创建表和插入数据,非常麻烦。
即使公用同一个开发服务器,如果同时修改同一个表也容易相互影响。
使用开发服务器,如果开发服务器需要内网才可连接,回去就不方便。
使用H2数据库就不容易相互影响。
三、编码
首先看项目结构
本示例非常简单,提供了一个UserInfo实体,建表语句放在schema.sql中,data.sql插入几条记录。
application配置文件不同环境之间是隔离的,我们这个示例项目,测试时设置为test环境。
application-test.properties 文件
spring.application.name=h2-test-demo
# 数据库配置
spring.datasource.url=jdbc:h2:mem:test;DB_CLOSE_DELAY=-1;MODE=MySQL
spring.datasource.username=
spring.datasource.password=
spring.datasource.driver-class-name=org.h2.Driver
spring.datasource.schema=schema.sql
spring.datasource.data=data.sql
#mybatis配置
mybatis.config-location=classpath:mybatis/mybatis-config.xml
mybatis.mapper-locations=classpath*:mybatis/mappers/*.xml
Application类
@SpringBootApplication
@MapperScan("h2demo.mapper")
public class Application {
public static void main(String[] args) {
SpringApplication.run(Application.class, args);
}
}
单元测试基类
@RunWith(SpringRunner.class)
@ActiveProfiles(value="test")
@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.NONE)
public class BaseMapperTest {
}
使用非常简单,只要继承该基类即可。
public class UserInfoMapperTest extends BaseMapperTest {
@Resource
private UserInfoMapper userInfoMapper;
@Test
public void deleteById() {
int rows = userInfoMapper.deleteById(1L);
Assertions.assertThat(rows).isGreaterThan(0);
}
}
项目的pom.xml文件
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.chujianyun</groupId>
<artifactId>h2-unit-test-demo</artifactId>
<version>1.0-SNAPSHOT</version>
<properties/>
<dependencies>
<!-- https://mvnrepository.com/artifact/org.springframework.boot/spring-boot-starter-web -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
<version>2.1.7.RELEASE</version>
</dependency>
<!-- https://mvnrepository.com/artifact/org.springframework.boot/spring-boot-starter-test -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<version>2.1.7.RELEASE</version>
<scope>test</scope>
</dependency>
<!-- https://mvnrepository.com/artifact/org.mybatis.spring.boot/mybatis-spring-boot-starter -->
<dependency>
<groupId>org.mybatis.spring.boot</groupId>
<artifactId>mybatis-spring-boot-starter</artifactId>
<version>2.1.0</version>
</dependency>
<!-- https://mvnrepository.com/artifact/com.h2database/h2 -->
<dependency>
<groupId>com.h2database</groupId>
<artifactId>h2</artifactId>
<version>1.4.199</version>
<scope>test</scope>
</dependency>
<!-- https://mvnrepository.com/artifact/junit/junit -->
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.12</version>
<scope>test</scope>
</dependency>
<!-- https://mvnrepository.com/artifact/org.projectlombok/lombok -->
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>1.18.8</version>
<scope>provided</scope>
</dependency>
</dependencies>
<build>
<pluginManagement><!-- lock down plugins versions to avoid using Maven defaults (may be moved to parent pom) -->
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-surefire-plugin</artifactId>
<version>${maven-surefire-plugin.version}</version>
</plugin>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
<plugin>
<artifactId>maven-clean-plugin</artifactId>
<version>3.0.0</version>
</plugin>
<!-- see http:// maven.apache.org/ref/current/maven-core/default-bindings.html#Plugin_bindings_for_jar_packaging -->
<plugin>
<artifactId>maven-resources-plugin</artifactId>
<version>3.0.2</version>
</plugin>
<plugin>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.7.0</version>
</plugin>
<plugin>
<artifactId>maven-surefire-plugin</artifactId>
<version>2.20.1</version>
</plugin>
<plugin>
<artifactId>maven-jar-plugin</artifactId>
<version>3.0.2</version>
</plugin>
<plugin>
<artifactId>maven-install-plugin</artifactId>
<version>2.5.2</version>
</plugin>
<plugin>
<artifactId>maven-deploy-plugin</artifactId>
<version>2.8.2</version>
</plugin>
<!-- 指定外部的jar包 -->
<plugin>
<artifactId>maven-compiler-plugin</artifactId>
<version>2.3.2</version>
<configuration>
<source>1.8</source>
<target>1.8</target>
<encoding>UTF-8</encoding>
<compilerArguments>
<extdirs>${project.basedir}/src/main/resources/lib</extdirs><!--指定外部lib-->
</compilerArguments>
</configuration>
</plugin>
</plugins>
</pluginManagement>
</build>
</project>
项目的地址:aaa@qq.com:chujianyun/springboot-h2-test-demo.git
四、Learn More
4.1 调试
可以在插入语句处断点,然后单步进入源码查看整个执行流程,注意观察参数。
注意观察左下角的调用栈,通过调用栈切换代码层次来学习源码。
4.2 源码
可以通过配置文件
点击数据源配置下面几项,可以跳转到spring-boot-autoconfigure.jar中查看参数对应的自动配置的类。
点击mybatis配置下面几项,可以跳转到mybatis-spring-boot-autoconfigure.jar中查看对应的配置类和处理代码。
大家还可以进入h2的驱动jar包和mybatis的jar中查看源码的逻辑。
通过这些可以学到更多内容。
五、总结
本文主要讲述SpringBoot使用H2内存数据库进行单元测试的案例。
在此也提倡大家对DAO层采用内存数据库的方式进行单元测试。
对于Service层的测试建议使用mockito,通过mock依赖的其他服务来检测当前模块逻辑是否正确的方式进行测试。
最后讲述通过调试和读源码来学到更多细节。
总之建议大家一定要重视单元测试,尽可能地避免失误,通过单元测试提高编码的质量,另外学习不要止步与实现功能。
推荐阅读
-
SpringBoot使用H2内存数据库单元测试的代码示例
-
SpringBoot使用LomBok的示例代码
-
springboot整合H2内存数据库实现单元测试与数据库无关性
-
springboot整合H2内存数据库实现单元测试与数据库无关性
-
SpringBoot使用Aspect切面拦截打印请求参数的示例代码
-
详解在SpringBoot中使用MongoDb做单元测试的代码
-
SpringBoot使用prometheus监控的示例代码
-
详解IDEA中便捷内存数据库H2的最简使用方式
-
SpringBoot使用H2嵌入式数据库的实例代码
-
SpringBoot中使用Filter和Interceptor的示例代码