上个月在博客中,讲了怎么使用dbunit帮助测试dao。但是在使用过程中,发现,使用dbunit的过程依然很繁琐。因此考虑对dbunit的使用做一些封装。期间发现开源工具Unitils已经很好的完成了这个工作。Unitils,由多个模块构成。 DatabaseModule,DbUnitModule,HibernateModule ,MockModule,EasyMockModule,InjectModule,SpringModule
我感兴趣的是dbunit和spring整合的两个模块。结合这两个模块可以很方便的完成dao的测试。
首先包含,unitils的库和依赖库
<dependency> <groupId>org.unitils</groupId> <artifactId>unitils</artifactId> <version>2.4</version> <scope>test</scope> </dependency>
在classpath下配置 unitils.properties配置文件
database.driverClassName=com.mysql.jdbc.Driver database.url=jdbc:mysql://localhost/subcenter database.userName=subcenter database.password=subcenter database.schemaNames=subcenter database.dialect=mysql
在测试类上声明@RunWith(UnitilsJUnit4TestClassRunner.class),或者集成Untils提供的基类org.unitils.UnitilsJUnit3,org.unitils.UnitilsJUnit4,org.unitils.UnitilsTestNG
配置使用spring
在测试类中声明spring的配置文件
@SpringApplicationContext( { "classpath:persistence-test.xml", "classpath:beans.xml" })
在测试类中注入Spring bean
@SpringBeanByType UserDAO target; //或者注入Applicationcontext @SpringApplicationContext ApplicationContext applicationcontext;
前面在unitisl配置文件中,制定了数据库连接,为了让spring中的bean使用相同的数据连接,可以在spring中使用unitils提供的数据源
<bean id="datasource" class="org.unitils.database.UnitilsDataSourceFactoryBean" />
这样unitils提供的测试数据插入和验证操作,能够和dao运行在同一个事务下。
同样的unitils也可以制定测试方法在执行后回滚数据库,撤销的数据库的更改。在测试类或方法上声明
@Transactional(TransactionMode.ROLLBACK)
最后测试类应该为:
@RunWith(UnitilsJUnit4TestClassRunner.class) @SpringApplicationContext( { "classpath:persistence-test.xml", "classpath:beans.xml" }) @Transactional(TransactionMode.ROLLBACK) public class PromotionInfoDAOTest { @SpringBeanByType PromotionInfoDAO target; }
使用unitils插入测试数据:
在测试方法上使用@DataSet注解,让unitils把以dbunit的FlatXmlDataSet格式制定的数据插入到数据库,默认使用的插入操作是CLEAN_INSERT,即插入前先清空涉及到的表。
在测试方法上使用@ExpectedDataSet注解,让unitils验证操作后的数据库。
@Test @DataSet("PromotionInfoDAOTest-emputy.xml") @ExpectedDataSet("PromotionInfoDAOTest-after.xml") public void add() throws Exception { PromotionInfoDO promotion = DBUnitUtils.createBean(afterDataset, "promotion", PromotionInfoDO.class); promotion.setCategory(new PromotionCategoryDO(2)); target.insert(promotion); }
使用@DataSet时,可以指定一个空的XML文件,让unitils清空数据库。例如
<?xml version="1.0" encoding="UTF-8"?> <dataset> <promotion /> </dataset>
使用@ExpectedDataSet验证时,unitils只会比较出现在xml文件中的字段和表。那么自增ID等不方便比较的字段可以不用在xml文件中配置,不进行比较。
是测试时,比如测试一个插入操作,我们首先写一个XML配置文件,写上要插入的表数据,然后创建一个相同字段的Bean,插入到数据库中,最后验证相同。
这个工程中,重复配置了两篇数据,不符合DYR原则。因此,我写了一个小工具类,可以从dbunits的FlatXmlDataset文件中创建Bean。
PromotionInfoDO promotion = DBUnitUtils.createBean(afterDataset, "promotion", PromotionInfoDO.class);
/** * * 从dbunit的FlatXmlDataSet格式的xml文件创建bean * * @author mshijie * */ public class DBUnitUtils { /** * 从dbunit的flatXmlDataSet中,创建多个bean * * @param <T> * @param file * @param clazz * @param ignoredProps * @return * @throws Exception */ public static <T> List<T> createBeans(String file, String tableName, Class<T> clazz) throws Exception { //................................ } /** * 从dbunit的flatXmlDataSet中,创建bean * * @param <T> * @param file * @param clazz * @param ignoredProps * @return * @throws Exception */ public static <T> T createBean(String file, String tableName, Class<T> clazz) throws Exception { //................................ } //............................................................... }
完整代码见附件