Spock实践(一)
背景
单元测试算是一个老生常谈的问题了,在实际的情况中,总是需要在单元测试与进度之间进行一个权衡,而往往实际上权衡时都是偏向进度一方,甚至很多自信的开发者都不推崇进行单元测试的编写,觉得单元测试费时费力,并且在需求调整又需要重新进行单元测试的编写,其实还有很大一部分原因是因为目前在Spring
体系中,常用的单元测试框架就是基于PowerMock
或者MockTo
等,由于这些框架依赖Spring
容器,所以在编写过程需要频繁的启动Spring
容器进行单元测试的测试,导致过程比较繁琐。
最近看到一篇美团的2021博客点击率TOP10
中的一篇Spock单元测试框架介绍以及在美团优选的实践,使用全新的Spock
框架来进行单元测试,这个框架的好处,无需依赖Spring
容器来进行单元测试,并且结合groovy
动态语言的特点,提供了一些标签,并采用简单、通用、结构化的描述语言,让编写测试代码更加简洁、高效。具体细节参考美团的那篇技术博客。
尝试
对于dao层抽象
在将这篇博客中的一些例子简单跑过之后,Spock
确实在单元测试的编写上比较简单且直观,但是由于它不依赖于Spring
容器,导致了原来Spring
框架为我们封装的一些特性无法使用,比如在我们应用中,到处都是通过tk.mybatis
或者mybatis plus
的一些通过接口api
来动态化SQL
,而无需进行手动编写SQL
。这些特性实际上是通过Spring
容器中在创建特定bean
对象时通过spring
的扩展点进行处理的。在美团的那篇博客中也提到了如果想测试dao
层,可以通过MyBatis的SqlSession
启动mapper
实例,但是这种方式仅仅获取到的是最基础的ibatis
的代理对象,没有了tk
或者是mp
相关的增强。
由于目前只是想简单的引入Spock
到某一个服务中,在实际的业务逻辑中,并不确定引入Spock
对单元测试的编写是否会有提高,所以这里仅仅研究了如何在不依赖spring
容器的情况下,伪造tk.mybatis
查询时的mapper
对象。
跟踪Springbean
对象的创建过程,发现tk.mybatis
主要是靠tk.mybatis.spring.mapper.MapperFactoryBean
(注意包路径,ibatis
包下有一个同名类)来进行一些增强处理。所以创建一个工具类,专门用来获取对应的mapper
代理对象。
1 | /** |
H2内存数据库
在美团的这篇博客中,推荐使用H2
数据库进行数据的隔离,在对H2
进行一些了解后发现H2
对mysql
的一些语句并不支持,比如建表时的索引之类,所以需要修改原本的建表脚本,在进行一些字段迭代时,可能会比较繁琐。
通过直接使用java.sql.Connection
对象来创建数据库连接,并执行建表语句。
1 | # AUTO_SERVER=TRUE 默认情况下只能单个连接,这个配置用来开启多个连接 |
执行处理代码如下:
1 | static void executeSql(String sqlPath) { |
DbUnit的使用
根据美团的这篇博客中,使用DbUnit
来进行数据层数据的访问控制,也就是在初始化某个单元测试接口时进行的一些准备数据脚本的执行,
基于xml脚本文件
在经过测试发现,DbUnit
是通过xml
文件来编写插入数据的脚本,这就导致写xml
插入数据脚本文件也会花费一些工作量。以下为一个示例,假设要为某个接口准备几十条数据,估计准备数据的过程要疯,后期可以看看DbUnit
有没有接口可以通过SQL
转换为这个xml
文件,或者自己实现一个接口,将SQL
转换为xml
文件来减少工作流。
1 |
|
基于csv脚本文件
DbUnit
还支持通过.csv
文件进行数据准备,但是比较繁琐的是它好像不能执行具体的文件,需要执行一个目录,并且目录下需要创建一个table-ordering.txt
文件,内容为此目录下要执行的csv
文件名称,同时csv
文件的名称需与表名保持一致。
自定义查询SQL语句
对于在xxxMapper.xml
文件中的查询语句,目前不知道因为什么原因,字段值无法赋值到实体上,需要通过as
关键字将下划线字段别名为驼峰形式才可在实体中获取到,这个问题无疑是致命的,导致基本上所有的mapper.xml
文件都无法进行单元测试。