在开发中经常会遇到持久化层的单元测试,如果直接连 MySQL 那就需要本地提前安装好,并且在每个测试 case 上加回滚操作,这当然是能做到的,但终究有种很”重“ 的感觉。使用 H2 内存数据库,就可以实现随地单测,并且每个测试 case 执行完毕后 session 自动关闭,从而批量跑单测的时候(CICD)多个 case 之间不会相互影响。
所以搭建内存数据库用作持久化层的单元测试是很有必要的。
搭建网上有很多这方面的博客,对对错错那就要靠自己踩坑甄别了,一番操作后做以记录。
添加依赖---spring: profiles: unit-test jpa: open-in-view: true properties: hibernate: enable_lazy_load_no_trans: true hibernate: ddl-auto: create globally_quoted_identifiers: true show-sql: true database-platform: org.hibernate.dialect.H2Dialect datasource: platform: h2 driver-class-name: org.h2.Driver url: jdbc:h2:mem:testDB;DB_CLOSE_DELAY=-1;MODE=LEGACY
单元测试 demo@SpringBootTest@ActiveProfiles("unit-test")class JpaApiLogRepositoryTest { @Autowired private JpaApiLogRepository jpaApiLogRepository; @Test void should_save_api_log_succeed() { ApiLog apiLog = TestFigure.getApiLog("diego2", "/api/v1/nlp/test/", "GET"); jpaApiLogRepository.save(apiLog); Optional optional = jpaApiLogRepository.findById(apiLog.getId()); assertThat(optional.isPresent(), is(true)); ApiLog fetched = optional.get(); assertThat(fetched.getId(), is(notNullValue())); assertThat(fetched.getTraceId(), is(apiLog.getTraceId())); assertThat(fetched.getMethod(), is(apiLog.getMethod())); assertThat(fetched.getPath(), is(apiLog.getPath())); assertThat(fetched.getRequestParams(), is(apiLog.getRequestParams())); assertThat(fetched.getRequestBody(), is(apiLog.getRequestBody())); assertThat(fetched.getResponseStatus(), is(apiLog.getResponseStatus())); assertThat(fetched.getRequestTime().getTime(), is(apiLog.getRequestTime().getTime())); assertThat(fetched.getResponseTime().getTime(), is(apiLog.getResponseTime().getTime())); assertThat(fetched.getTimeUsed(), is(apiLog.getTimeUsed())); assertThat(fetched.getRemark(), is(apiLog.getRemark())); }}
小问题有时候会遇到 h2 不支持一些 sql 语法,这时就需要见招拆招,具体问题具体对待了。有一种场景是:sql 中的字段命中了 h2 的关键子导致执行失败。比如:
@Entity@Datapublic class Student { @Id @GeneratedValue(strategy = GenerationType.AUTO) private Long id; private String name; private int order;}
order 是 h2 的关键字, 报异常org.hibernate.exception.SQLGrammarException: could not prepare statement。
解决办法:
@Column(name = "`order`")private int order;