给spring-boot测试提供unitils支持的开源项目
2018-07-09 01:33
543 查看
一、unitils测试框架优缺点介绍
在unitils的支持下,xml配置的spring项目在测试时,有如下好处:
1、利用注解@DataSet、@ExpectedDataSet来准备数据和校验结果数据,每次运行测试用例不用重新准备数据。
2、利用@Transactional来配置测试时的事务模式:COMMIT(测试后提交数据)、ROLLBACK(测试后回滚数据,不会污染测试数据库)
3、可以基于单独的单元测试数据库进行单元测试
4、等等
利用unitils来进行单元测试,好处多多,单元测试对于开发人员来说,至关重要,首先可以检查程序是否按照预期运行,其次,过段时间后,只需要运行一下单元测试,就可以检车程序是否被修改出错,及时检查出问题。
但是,上述基于unitils的spring项目的单元测试都是在xml配置文件的基础之上,目前很多项目都是spring-boot项目,最新的unitils-3.4.6也不支持spring-boot的项目,因此,这里在查看unitils的源码的基础上,做了一个小的开源项目:spring-boot-unitils-starter来给spring-boot项目提供基于unitils支持。
二、spring-boot-unitils-starter项目介绍
1、项目结构如下
2、问题分析
在一中介绍到了unitils只支持xml形式的spring 项目,spring-boot项目是去配置化了,而且查看unitils的源码得知,测试中用到的bean都是从一个applicationContext中获取之后再设置到对应的属性(通过注解@SpringBeanByType、@SpringBeanByName来实现)中,因此spring-boot-unitils-starter项目的重点就是将spring-boot应用的applicationContext获取到然后设置到unitils中的applicationContext。
3、主要功能点
3.1、spring-boot应用applicationContext的获取与设置
这里的@ConditionalOnClass就是为了在测试的时候才声明这个bean(ConfigurableApplicationContextAware),UnitilsBootBlockJUnit4ClassRunner是单元测试的ClassRunner。
3.2、spring项目运行unitils的核心类SpringBootModule
原始的unitils提供的是SpringModule,applicationContext就是该类的一个属性,并且只能get,不能set,为了和原始的SpringModule区分开,并且考虑到我们测试的应用是spring-boot,因此这里就新建了SpringBootModule,修改applicationContext为static,并且给applicationContext设置了静态set方法。
3.3、SpringBootApplicationContextFactory的作用就是去掉xml的配置,避免启动出错
这里的setConfigurableApplicationContext方法也可以设置applicationContext。
3.4、结合spring和unitils的classRunner:UnitilsBootBlockJUnit4ClassRunner
这个类是结合了原始unitils中的UnitilsBlockJUnit4ClassRunner和spring-test中的SpringJUnit4ClassRunner,使其在初始化spring容器后,还可以unitils相关的初始化。
3.5、添加xls文件支持:MultiSchemaXlsDataSetReader和MultiSchemaXlsDataSetFactory
MultiSchemaXlsDataSetReader和MultiSchemaXlsDataSetFactory添加后,就可以支持@DataSet中的xls文件。
3.6、替换datasource:DataSourcePostProcessor
测试时,替换容器中的datasource,使用unitils来进行事务管理
三、测试样例
1、unitils.properties配置文件
module的配置:
第一行指定了module,springBoot是spring-boot-unitils-starter中的,unitils.module.springBoot.className指定了其对应的类。
上述指定了单元测试数据库,一般只有这里根据自己的情况修改。
上述指定了@DataSet、@ExpectedDataSet的文件解析和applicationContextFactory的类位置,这里如果是xls形式的数据文件,则不用修改,如果是xml形式的数据,只需要修改如下的配置值即可
2、测试主类
注解@RunWith指定了我们定制的ClassRunner:UnitilsBootBlockJUnit4ClassRunner,@SpringBootTest指定了spring-boot的应用启动类:SampleTestApplication,因为我们需要让spring容器识别到ConfigurableApplicationContextAware,因此,需要新建一个类来让ConfigurableApplicationContextAware(在包com.unitils.boot.autoconfigure下)被扫描到,这里新建了SampleTestApplication,其代码如下:
3、数据准备文件getUserInfo.xls
列名就是表的列名,sheet的名字就是表名。
四、扩展
项目只是在每次跑一个单元测试方法的时候用过,其他场景还没用过,不知道会出什么问题;项目也没经过完备的测试,可能存在未知BUG,后续后有针对性的完善。
项目已经经过测试,满足单元测试需求,在单个和多个测试同时跑的情况下,表现良好。
在此基础之上修改得到的成果是:spring-boot-unitils-starter可以在maven中央库下载了,对应的maven依赖如下:
附:项目的完整代码见:https://github.com/yangjianzhou/spring-boot-unitils
在unitils的支持下,xml配置的spring项目在测试时,有如下好处:
1、利用注解@DataSet、@ExpectedDataSet来准备数据和校验结果数据,每次运行测试用例不用重新准备数据。
2、利用@Transactional来配置测试时的事务模式:COMMIT(测试后提交数据)、ROLLBACK(测试后回滚数据,不会污染测试数据库)
3、可以基于单独的单元测试数据库进行单元测试
4、等等
利用unitils来进行单元测试,好处多多,单元测试对于开发人员来说,至关重要,首先可以检查程序是否按照预期运行,其次,过段时间后,只需要运行一下单元测试,就可以检车程序是否被修改出错,及时检查出问题。
但是,上述基于unitils的spring项目的单元测试都是在xml配置文件的基础之上,目前很多项目都是spring-boot项目,最新的unitils-3.4.6也不支持spring-boot的项目,因此,这里在查看unitils的源码的基础上,做了一个小的开源项目:spring-boot-unitils-starter来给spring-boot项目提供基于unitils支持。
二、spring-boot-unitils-starter项目介绍
1、项目结构如下
2、问题分析
在一中介绍到了unitils只支持xml形式的spring 项目,spring-boot项目是去配置化了,而且查看unitils的源码得知,测试中用到的bean都是从一个applicationContext中获取之后再设置到对应的属性(通过注解@SpringBeanByType、@SpringBeanByName来实现)中,因此spring-boot-unitils-starter项目的重点就是将spring-boot应用的applicationContext获取到然后设置到unitils中的applicationContext。
3、主要功能点
3.1、spring-boot应用applicationContext的获取与设置
@Configuration @ConditionalOnClass(UnitilsBootBlockJUnit4ClassRunner.class) public class ConfigurableApplicationContextAware implements InitializingBean { @Autowired private ConfigurableApplicationContext configurableApplicationContext; @Override public void afterPropertiesSet() throws Exception { SpringBootModule.setApplicationContext(configurableApplicationContext); } }
这里的@ConditionalOnClass就是为了在测试的时候才声明这个bean(ConfigurableApplicationContextAware),UnitilsBootBlockJUnit4ClassRunner是单元测试的ClassRunner。
3.2、spring项目运行unitils的核心类SpringBootModule
原始的unitils提供的是SpringModule,applicationContext就是该类的一个属性,并且只能get,不能set,为了和原始的SpringModule区分开,并且考虑到我们测试的应用是spring-boot,因此这里就新建了SpringBootModule,修改applicationContext为static,并且给applicationContext设置了静态set方法。
private static ApplicationContext applicationContext; public static void setApplicationContext(ApplicationContext applicationContext) { SpringBootModule.applicationContext = applicationContext; }
3.3、SpringBootApplicationContextFactory的作用就是去掉xml的配置,避免启动出错
public class SpringBootApplicationContextFactory implements ApplicationContextFactory { private static ConfigurableApplicationContext configurableApplicationContext ; public ConfigurableApplicationContext createApplicationContext(List<String> locations) { return configurableApplicationContext; } public static void setConfigurableApplicationContext(ConfigurableApplicationContext configurableApplicationContext) { SpringBootApplicationContextFactory.configurableApplicationContext = configurableApplicationContext; } }
这里的setConfigurableApplicationContext方法也可以设置applicationContext。
3.4、结合spring和unitils的classRunner:UnitilsBootBlockJUnit4ClassRunner
这个类是结合了原始unitils中的UnitilsBlockJUnit4ClassRunner和spring-test中的SpringJUnit4ClassRunner,使其在初始化spring容器后,还可以unitils相关的初始化。
3.5、添加xls文件支持:MultiSchemaXlsDataSetReader和MultiSchemaXlsDataSetFactory
MultiSchemaXlsDataSetReader和MultiSchemaXlsDataSetFactory添加后,就可以支持@DataSet中的xls文件。
3.6、替换datasource:DataSourcePostProcessor
测试时,替换容器中的datasource,使用unitils来进行事务管理
@Component public class DataSourcePostProcessor implements BeanPostProcessor { @Override public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException { if (beanName.equals("dataSource")) { try { return new UnitilsDataSourceFactoryBean().getObject(); } catch (Exception exp) { throw new RuntimeException("replace database throw exception ,can not continue to process", exp); } } return bean; } }
三、测试样例
1、unitils.properties配置文件
unitils.modules=database,dbunit,springBoot unitils.module.springBoot.className=com.unitils.boot.SpringBootModule unitils.module.springBoot.runAfter=database unitils.module.springBoot.enabled=true #自扩展模块 unitils.module.dbunit.className=org.unitils.dbunit.DbUnitModule ############################################################################ ### Database模块相应配置 ### ############################################################################ ## Full qualified class name of an implementation of org.unitils.database.datasource.DataSourceFactory. This class is used # to provide a DataSource for all database unit tests and for the DBMaintainer. org.unitils.database.datasource.DataSourceFactory.implClassName=org.unitils.database.datasource.impl.DefaultDataSourceFactory #数据库事务类型 #可选:commit/rollback/disanled database.default.transaction.mode=commit ## 测试数据库 # 此数据库驱动类型 database.driverClassName=com.mysql.jdbc.Driver # 此数据库连接信息 database.url=jdbc:mysql://127.0.0.1/test # 此数据库连接用户名 database.userName=root # 此数据库连接用户密码 database.password=12345678 # 此数据库连接的schema database.schemaNames=test # 此数据库数据库类型:oracle/mysql/postgres等 database.dialect=mysql # 不同数据库对应的实现 # Fully qualified classnames of the different, dbms specific implementations of org.dbmaintain.database.Database.implClassName org.dbmaintain.database.Database.implClassName.oracle=org.dbmaintain.database.impl.OracleDatabase org.dbmaintain.database.Database.implClassName.mysql=org.dbmaintain.database.impl.MySqlDatabase # 是否支持初数据库始化脚本,默认关闭(可以通过脚本每次重建数据库等) # The database maintainer is disabled by default. updateDataBaseSchema.enabled=true #This table is by default not created automatically dbMaintainer.autoCreateExecutedScriptsTable=true # Indicates whether a from scratch update should be performed when the previous update failed, but # none of the scripts were modified since that last update. If false a new update will be tried only when # changes were made to the script files. dbMaintainer.keepRetryingAfterError.enabled=true dbMaintainer.script.locations= ############################################################################ ### Database模块相应配置 ### ############################################################################ # Dbunit中DataSet和ExpectedDataSet的数据准备实现类,(也可以用Excel准备数据,需要替换实现类) DbUnitModule.DataSet.factory.default=com.unitils.boot.xls.MultiSchemaXlsDataSetFactory DbUnitModule.ExpectedDataSet.factory.default=com.unitils.boot.xls.MultiSchemaXlsDataSetFactory org.dbunit.database.IMetadataHandler.implClassName=org.dbunit.ext.mysql.MySqlMetadataHandler ## Dbunit中测试数据处理策略 # CleanInsertLoadStrategy:先删除dateSet中有关表的数据,然后再插入数据。 # InsertLoadStrategy:只插入数据。 # RefreshLoadStrategy:有同样key的数据更新,没有的插入。 # UpdateLoadStrategy: 有同样key的数据更新,没有的不做任何操作。 DbUnitModule.DataSet.loadStrategy.default=org.unitils.dbunit.datasetloadstrategy.impl.CleanInsertLoadStrategy # XSD generator dataSetStructureGenerator.xsd.dirName=/tmp/resources/xsd SpringModule.applicationContextFactory.implClassName=com.unitils.boot.util.SpringBootApplicationContextFactory
module的配置:
unitils.modules=database,dbunit,springBoot unitils.module.springBoot.className=com.unitils.boot.SpringBootModule
第一行指定了module,springBoot是spring-boot-unitils-starter中的,unitils.module.springBoot.className指定了其对应的类。
database.driverClassName=com.mysql.jdbc.Driver # 此数据库连接信息 database.url=jdbc:mysql://127.0.0.1/test # 此数据库连接用户名 database.userName=root # 此数据库连接用户密码 database.password=12345678 # 此数据库连接的schema database.schemaNames=test # 此数据库数据库类型:oracle/mysql/postgres等 database.dialect=mysql
上述指定了单元测试数据库,一般只有这里根据自己的情况修改。
DbUnitModule.DataSet.factory.default=com.unitils.boot.xls.MultiSchemaXlsDataSetFactory DbUnitModule.ExpectedDataSet.factory.default=com.unitils.boot.xls.MultiSchemaXlsDataSetFactory SpringModule.applicationContextFactory.implClassName=com.unitils.boot.util.SpringBootApplicationContextFactory
上述指定了@DataSet、@ExpectedDataSet的文件解析和applicationContextFactory的类位置,这里如果是xls形式的数据文件,则不用修改,如果是xml形式的数据,只需要修改如下的配置值即可
DbUnitModule.DataSet.factory.default=com.unitils.boot.xls.MultiSchemaXlsDataSetFactory DbUnitModule.ExpectedDataSet.factory.default=com.unitils.boot.xls.MultiSchemaXlsDataSetFactory
2、测试主类
package com.unitils.boot.controller; import com.unitils.boot.SampleTestApplication; import com.unitils.boot.util.UnitilsBootBlockJUnit4ClassRunner; import org.junit.Assert; import org.junit.Test; import org.junit.runner.RunWith; import org.springframework.boot.test.context.SpringBootTest; import org.unitils.database.annotations.Transactional; import org.unitils.database.util.TransactionMode; import org.unitils.dbunit.annotation.DataSet; import org.unitils.spring.annotation.SpringBeanByType; @RunWith(UnitilsBootBlockJUnit4ClassRunner.class) @SpringBootTest(classes = SampleTestApplication.class) @Transactional(value = TransactionMode.ROLLBACK) public class UserControllerTest { @SpringBeanByType private UserController userController ; @Test @DataSet(value = {"/data/getUserInfo.xls"}) public void test_getUsername(){ String username = userController.getUsername(3); Assert.assertNotNull(username); Assert.assertTrue(username.equals("wangwu")); } }
注解@RunWith指定了我们定制的ClassRunner:UnitilsBootBlockJUnit4ClassRunner,@SpringBootTest指定了spring-boot的应用启动类:SampleTestApplication,因为我们需要让spring容器识别到ConfigurableApplicationContextAware,因此,需要新建一个类来让ConfigurableApplicationContextAware(在包com.unitils.boot.autoconfigure下)被扫描到,这里新建了SampleTestApplication,其代码如下:
package com.unitils.boot; import org.mybatis.spring.annotation.MapperScan; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.context.annotation.ComponentScan; @SpringBootApplication @ComponentScan({"com.unitils.boot", "com.unitils.boot.autoconfigure"}) @MapperScan(basePackages = "com.unitils.boot.mapper") public class SampleTestApplication { public static void main(String[] args) { SpringApplication.run(SampleTestApplication.class, args); } }
3、数据准备文件getUserInfo.xls
列名就是表的列名,sheet的名字就是表名。
四、扩展
项目只是在每次跑一个单元测试方法的时候用过,其他场景还没用过,不知道会出什么问题;项目也没经过完备的测试,可能存在未知BUG,后续后有针对性的完善。
项目已经经过测试,满足单元测试需求,在单个和多个测试同时跑的情况下,表现良好。
在此基础之上修改得到的成果是:spring-boot-unitils-starter可以在maven中央库下载了,对应的maven依赖如下:
<dependency> <groupId>com.github.yangjianzhou</groupId> <artifactId>spring-boot-unitils-starter</artifactId> <version>1.1.0.RELEASE</version> </dependency>
附:项目的完整代码见:https://github.com/yangjianzhou/spring-boot-unitils
相关文章推荐
- 非Spring Boot Web项目 注册节点到Eureka Server并提供服务
- 使用Spring Boot开发Web项目(二)之添加HTTPS支持
- 使用Spring Boot开发Web项目(二)之添加HTTPS支持
- Spring Boot项目添加jsp支持
- 使用spring boot +Junit 测试 spring mvc 配置中心项目
- springboot 整合web项目支持jsp
- SpringBoot Maven项目 Helloworld 测试
- SpringBoot Helloworld 测试 Maven项目
- 使用Spring Boot开发Web项目(二)之添加HTTPS支持
- springboot项目 同时支持http、https
- springboot项目中使用MockMvc 进行测试
- Spring Boot项目实现从系统目录中下载指定文件(D盘下,测试文件1.txt)
- 开源项目推荐:e-example / Springboot+bootstrap + ……
- 使用Spring Boot开发Web项目(二)之添加HTTPS支持
- spring boot项目如何测试,如何部署
- SpringBoot项目中的多数据源支持的方法
- 利用spring提供的MockHttpServletRequest,直接测试项目的控制层controller
- (开源项目)基于springboot的后台管理系统基本框架
- 【xbin-store】基于springboot的分布式B2C电商开源项目
- SpringBoot项目中的多数据源支持