DAO层测试难点
可重复性,每次运行单元测试,得到的数据是重复的
独立性,测试数据与实际数据相互独立
数据库中脏数据预处理
不能给数据库中数据带来变化
DAO层测试方法
使用内存数据库,如H2。优点:无需清空无关数据;缺点:单元测试中需要进行数据库初始化过程,如果初始化过程复杂,单元测试工作量增大
使用dbunit。优点:数据库初始化简单,大大减轻单元测试工作量;缺点:目前官方提供jar包只支持xml格式文件,需要自己开发Excel格式文件
基于dbunit进行DAO单元测试
应用环境:Spring、Mybatis、MySql、Excel
配置文件
1. pom.xml
引入jar包,unitils整合了dbunit,database,spring,io等模块
<dependency> <groupId>org.unitils</groupId> <artifactId>unitils-core</artifactId> <version>3.4.2</version> </dependency> <dependency> <groupId>org.unitils</groupId> <artifactId>unitils-dbunit</artifactId> <version>3.4.2</version> </dependency> <dependency> <groupId>org.unitils</groupId> <artifactId>unitils-io</artifactId> <version>3.4.2</version> </dependency> <dependency> <groupId>org.unitils</groupId> <artifactId>unitils-database</artifactId> <version>3.4.2</version> </dependency> <dependency> <groupId>org.unitils</groupId> <artifactId>unitils-spring</artifactId> <version>3.4.2</version> </dependency> <dependency> <groupId>org.dbunit</groupId> <artifactId>dbunit</artifactId> <version>2.5.3</version> </dependency></div>
配置maven对resourcew文件过滤规则,如果不过滤maven会对resource文件重编码,导致Excel文件被破坏
<resources> <resource> <directory>src/test/resources</directory> <includes> <include>**/*.*</include> </includes> <filtering>false</filtering> </resource> </resources></div>
2. unitils.properties
在测试源码根目录中创建一个项目级别的unitils.properties配置文件,主要用于配置自定义拓展模块,数据加载等相关信息
#启用unitils所需模块 unitils.modules=database,dbunit #自定义扩展模块,加载Excel文件,默认拓展模块org.unitils.dbunit.DbUnitModule支持xml unitils.module.dbunit.className=org.agoura.myunit.module.MyDbUnitModule #配置数据库连接 database.driverClassName=com.mysql.jdbc.Driver database.url=jdbc:mysql://127.0.0.1:3306/teams?autoReconnect=true&useUnicode=true&characterEncoding=utf-8 database.userName=root database.password=agoura #配置为数据库名称 database.schemaNames=teams #配置数据库方言 database.dialect=mysql #需设置false,否则我们的测试函数只有在执行完函数体后,才将数据插入的数据表中 unitils.module.database.runAfter=false #配置数据库维护策略.请注意下面这段描述 # If set to true, the DBMaintainer will be used to update the unit test database schema. This is done once for each # test run, when creating the DataSource that provides access to the unit test database. updateDataBaseSchema.enabled=true #配置数据库表创建策略,是否自动建表以及建表sql脚本存放目录 dbMaintainer.autoCreateExecutedScriptsTable=true dbMaintainer.keepRetryingAfterError.enabled=true dbMaintainer.script.locations=src/main/resources/dbscripts #dbMaintainer.script.fileExtensions=sql #数据集加载策略 #CleanInsertLoadStrategy:先删除dateSet中有关表的数据,然后再插入数据 #InsertLoadStrategy:只插入数据 #RefreshLoadStrategy:有同样key的数据更新,没有的插入 #UpdateLoadStrategy:有同样key的数据更新,没有的不做任何操作 DbUnitModule.DataSet.loadStrategy.default=org.unitils.dbunit.datasetloadstrategy.impl.CleanInsertLoadStrategy #配置数据集工厂,自定义 DbUnitModule.DataSet.factory.default=org.agoura.myunit.utils.MultiSchemaXlsDataSetFactory DbUnitModule.ExpectedDataSet.factory.default=org.agoura.myunit.utils.MultiSchemaXlsDataSetFactory #配置事务策略 commit、rollback 和disabled;或者在代码的方法上标记@Transactional(value=TransactionMode.ROLLBACK) #commit 是单元测试方法过后提交事务 #rollback 是回滚事务 #disabled 是没有事务,默认情况下,事务管理是disabled DatabaseModule.Transactional.value.default=commit #配置数据集结构模式XSD生成路径,可以自定义目录,但不能为空 dataSetStructureGenerator.xsd.dirName=src/main/resources/xsd dbMaintainer.generateDataSetStructure.enabled=true #文件相对路径是否是测试类文件路径,false表示resource根目录 dbUnit.datasetresolver.prefixWithPackageName=false</div>
3. spring-mybatis-unitils.xml
<?xml version="1.0" encoding="GBK"?> <beans xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:context="http://www.springframework.org/schema/context" xmlns="http://www.springframework.org/schema/beans" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.1.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.1.xsd"> <context:component-scan base-package="com.agoura.agoura"/> <context:property-placeholder location="classpath:jdbc_dbcp.properties"/> <!--<util:properties id="jdbc_dbcp" />--> <bean id="dataSource" class="org.unitils.database.UnitilsDataSourceFactoryBean"/> <!-- spring和MyBatis整合,不需要mybatis的配置映射文件 --> <bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean"> <property name="dataSource" ref="dataSource"/> <!-- 自动扫描mapping.xml文件 --> <property name="mapperLocations" value="classpath*:com/agoura/agoura/mapper/xml/*.xml"></property> </bean> <!-- DAO接口所在包名,Spring会自动查找其下的类 --> <bean class="org.mybatis.spring.mapper.MapperScannerConfigurer"> <property name="basePackage" value="com.agoura.agoura.mapper"/> <property name="sqlSessionFactoryBeanName" value="sqlSessionFactory"></property> </bean> <!-- (事务管理)transaction manager, use JtaTransactionManager for global tx --> <bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager"> <property name="dataSource" ref="dataSource"/> </bean> </beans></div>
dbunit执行流程
dbunit通过@DataSet注解读取模拟数据Excel文件,流程如下:
Excel文件 --> @DataSet --> DbUnitModule --> DataSetFactory --> 数据库(MySql)</div>
@DataSet:将指定路径下Excel文件加载到DbUnitModule中
DbUnitModule:对传入文件进行预处理,源代码中对传入的xml文件copy一份临时文件,并将临时文件交给DataSetFactory处理,处理完后再删除临时文件
DataSetFactory:将读取的Excel数据转换为MultiSchemaDataSet,准备放入数据库中
由于原代码DbUnitModule中只有对xml文件的预处理,而我们是要对Excel文件进行预处理,所以需要对DbUnitModule进行重写。重写内容为:完善DbUnitDatabaseConnection连接;针对Excel文件,修改预处理实现;修改文件处理后续操作。示例如下: