当前位置: 首页 > 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.lryc.cn/news/585985.html

相关文章:

  • 多 Agent 强化学习实践指南(一):CTDE PPO 在合作捕食者-猎物游戏中的应用详解
  • 引入了模块但没有使用”,会不会被打包进去
  • 【C++小白逆袭】内存管理从崩溃到精通的秘籍
  • c++反射实现
  • 张量数值计算
  • 跨系统开发代码换行符如何解决
  • 每日一SQL 【销售分析 III】
  • 试用了10款翻译软件后,我只推荐这一款!完全免费还超好用
  • 大模型KV缓存量化误差补偿机制:提升推理效率的关键技术
  • Qt6中出现 OpenCV(4.10.0) Error: Assertion failed
  • 第10讲——一元函数积分学的几何应用
  • 创建 UIKit 项目教程
  • 在 Java 中,计算两个 Integer 类型表示的合格数量与总数量的合格率,并保留四位小数,推荐使用 BigDecimal 来确保精度
  • springboot+swagger2文档从swagger-bootstrap-ui更换为knife4j及文档接口参数不显示问题
  • 股票的k线
  • 从基础加热到智能生态跨越:艾芬达用创新重构行业价值边界!
  • 人工智能自动化编程:传统软件开发vs AI驱动开发对比分析
  • 【科研绘图系列】R语言绘制小提琴图
  • 【TGRS 2025】可变形交互注意力Deform-Interac-Att,即插即用,涨点神器!
  • 【八股消消乐】Kafka集群 full GC 解决方案
  • 系统分析师-计算机系统-输入输出系统
  • 计算机视觉与深度学习 | 基于Matlab的多特征融合可视化指纹识别系统(附完整代码)
  • 3 c++提高——STL常用容器(一)
  • 深度学习图像分类数据集—铜片划痕识别分类
  • RocketMQ-
  • 基于springboot+Vue的二手物品交易的设计与实现
  • MySQL 内外连接
  • 仅27M参数!SamOutVX轻量级语言模型刷新认知,小身材也有大智慧
  • 贪心算法题解——跳跃游戏【LeetCode】
  • day68—DFS—二叉树的所有路径(LeetCode-257)