当前位置: 首页 > news >正文

H2在springboot的单元测试中的应用

为什么要使用H2做单元测试

1. 内存模式运行(零配置、零残留)

  • 无需安装:只需添加依赖即可使用,不依赖外部服务
  • 内存数据库:通过 jdbc:h2:mem:testdb 配置,数据完全存在于内存中
  • 测试后自动销毁:进程结束即消失,不会残留测试数据污染环境
  • 示例
    spring.datasource.url=jdbc:h2:mem:testdb;DB_CLOSE_DELAY=-1
    

2. 极速启动与执行

  • 毫秒级启动:比 MySQL/PostgreSQL 等传统数据库快 10-100 倍
  • 高性能:内存操作避免磁盘 I/O 瓶颈,加速测试执行
  • 统计对比
    数据库启动时间简单查询延迟
    H250ms0.1ms
    MySQL2s+1-10ms

3. 隔离性与可重复性

  • 独立实例:每个测试用例可创建独立数据库实例
  • 事务支持:配合 @Transactional 实现自动回滚
  • 代码示例
    @Test
    @Transactional // 测试后自动回滚
    public void testInsert() {repository.save(new Entity());assertEquals(1, repository.count()); // 断言生效
    } // 此处自动回滚,不影响其他测试
    

4. 兼容性强大

  • 多模式支持:可模拟其他数据库行为
    jdbc:h2:mem:test;MODE=MySQL # 模拟MySQL语法
    
  • 兼容常见SQL:支持标准 SQL、存储过程、触发器等功能
  • 规避问题:测试时暴露 SQL 兼容性问题,避免生产环境踩坑

5. 开发体验优化

  • 嵌入式控制台:通过 Web 界面实时查看测试数据
    spring.h2.console.enabled=true
    spring.h2.console.path=/h2-console
    
  • 自动初始化:配合 schema.sql/data.sql 快速构建测试场景
  • 与框架深度集成
    • Spring Boot 自动配置
    • MyBatis/JPA 无缝衔接
    • Testcontainers 兼容

6. CI/CD 友好

  • 无外部依赖:适合 Docker/CI 环境(如 GitHub Actions)
  • 资源占用低:仅需 2MB JAR 文件,不消耗额外内存
  • 并行测试:支持多线程同时运行测试类

对比传统数据库的劣势

场景H2 表现生产数据库表现
复杂查询优化无查询优化器有优化器
大数据量测试内存限制(约 1GB 数据)支持 TB 级数据
数据库特性测试部分语法不兼容完全兼容

何时适合用 H2?

  • 需要测试数据库专属特性(如 Oracle 的窗口函数)
  • 需要验证超大数据量性能
  • 测试特定数据库的兼容性(此时建议用 Testcontainers + 真实数据库)

最佳实践建议

  1. 基础测试:95% 的 CRUD/业务逻辑测试用 H2
  2. 集成测试:结合 @Testcontainers 补充真实数据库测试
  3. 配置示例
    # src/test/resources/application-test.yml
    spring:datasource:url: jdbc:h2:mem:testdb;MODE=MySQL;DB_CLOSE_DELAY=-1username: sapassword: ""
    

H2 通过极简的设计实现了单元测试的核心需求——快速、隔离、可重复,这正是它成为 Java 单元测试首选数据库的原因。

具体实践

首先看我的项目结构,非常的简单,而且大部分都是使用 mybatis-plus 的插件自动生成的

在这里插入图片描述
在这里插入图片描述
这里要说明几点:

  1. test/resources 中的 application配置文件如果存在的话,那么运行单元测试的时候是会首先加载这个配置文件的,而且这个配置文件在正常启动项目的时候,也不会被加载,所以,放心大胆的使用
  2. schema.sql 和 data.sql 文件:首先我们要知道 h2 数据库是内存数据库,也就是说,保留不下来表结构这些东西,不像mysql一样会将数据放到磁盘里面,所以每次我们使用 h2 的时候,都要重新的 建个表,加载一些初始数据

test下的配置文件如下

spring:datasource:url: spring.datasource.url=jdbc:h2:mem:testdb;DB_CLOSE_DELAY=-1;MODE=MySQL;IFEXISTS=TRUEdriver-class-name: org.h2.Driverusername: sapassword: ""# 初始化数据库脚本schema: classpath:schema.sqldata: classpath:data.sqlinitialization-mode: embeddedh2:console:enabled: truepath: /h2-console# MyBatis-Plus 配置
mybatis-plus:configuration:log-impl: org.apache.ibatis.logging.stdout.StdOutImpl # 输出SQL到控制台global-config:db-config:id-type: auto # 主键策略mapper-locations: classpath*:mapper/**/*.xml

pom 文件如下,pom文件不区分 测试和正式

<dependencies><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-web</artifactId></dependency><!--        mybatis-plus--><dependency><groupId>com.baomidou</groupId><artifactId>mybatis-plus-boot-starter</artifactId><version>3.5.1</version></dependency><!--        h2 数据库--><dependency><groupId>com.h2database</groupId><artifactId>h2</artifactId><scope>test</scope></dependency><!--        mysql驱动--><dependency><groupId>mysql</groupId><artifactId>mysql-connector-java</artifactId><version>8.0.26</version> <!-- 请根据需要选择合适的版本 --></dependency>

单元测试的书写

@SpringBootTest
@Transactional // 测试后自动回滚
public class StudentMapperTest {@Autowiredprivate StudentMapper studentMapper;@Testpublic void testSelectAll() {List<Student> students = studentMapper.selectList(null);Assertions.assertEquals(3, students.size()); // 验证data.sql中的数据}@Testpublic void testInsert() {Student newStudent = new Student();newStudent.setName("赵六");int result = studentMapper.insert(newStudent);Assertions.assertEquals(1, result);Student dbStudent = studentMapper.selectById(newStudent.getId());Assertions.assertEquals("赵六", dbStudent.getName());}
}

以上代码经过实地的验证,可以运行

http://www.dtcms.com/a/276109.html

相关文章:

  • skywalking镜像应用springboot的例子
  • try-catch-finally可能输出的答案?
  • Docker-镜像构建原因
  • C语言基础教程--从入门到精通
  • Spring Boot整合MyBatis+MySQL+Redis单表CRUD教程
  • STM32中的RTC(实时时钟)详解
  • R 语言绘制 10 种精美火山图:转录组差异基因可视化
  • JavaScript 常见10种设计模式
  • 码头智能哨兵:AI入侵检测系统如何终结废钢盗窃困局
  • Redis专题总结
  • MyBatis实现一对多,多对一,多对多查询
  • Golang操作MySQL json字段优雅写法
  • CPU缓存一致性协议:深入解析MESI协议与多核并发设计
  • HTML/JOSN复习总结
  • 7. JVM类加载器与双亲委派模型
  • PyQt5 — QTimeEdit 学习笔记
  • Java中的wait和notify、Condition接口的使用
  • 分类问题与多层感知机
  • pip国内镜像源一览
  • [es自动化更新] Updatecli编排配置.yaml | dockerfilePath值文件.yml
  • springboot+swagger2文档从swagger-bootstrap-ui更换为knife4j及文档接口参数不显示问题
  • 【高等数学】第三章 微分中值定理与导数的应用——第七节 曲率
  • DirectX Repair修复工具下载,.NET修复,DirectX修复
  • python 中 ‘5‘ 和 5 有什么本质区别?
  • 【深度学习】 1 Deep Learning
  • 12. JVM的垃圾回收器
  • LangChain 代理(Agents)学习
  • 网页五子棋-对战
  • python学习打卡:DAY 37 早停策略和模型权重的保存
  • web网站无法抓包排查;burp无法抓包情况