引述:程序测试对保障应用程序正确 性而言,其重要性怎么样强调都不为过。JUnit是必须事先掌握的测试框架,大多数测试框架和测试工具都在此基础上扩展而来,Spring对测试所提供的 帮助类也是在JUnit的基础上进行演化的。直接使用JUnit测试基于Spring的应用存在诸多不便,不可避免地须要将大量的精力用于应付测试夹具准 备、测试现场恢复、访问测试数据操做结果等边缘性的工做中。Mockito、Unitils、Dbunit等框架的出现,这些问题有了很好的解决方案,特 别是Unitils结合Dbunit对测试DAO层提供了强大的支持,大大提升了编写测试用例的效率和质量。
Unitils海纳百川(Junit,dbunit,mockito spring hibernate and so on..),以打造一个在实际应用开发中真正实战的测试框架,是致力于应用实战的开发者不得不学习的开源框架。
Unitils概述
Unitils测试框架目的是让单元测试变得更加容易和可维护。Unitils构建在DbUnit与EasyMock项目之上并与JUnit和 TestNG相结合。支持数据库测试,支持利用Mock对象进行测试并提供与Spring和Hibernate相集成。Unitils设计成以一种高度可 配置和松散耦合的方式来添加这些服务到单元测试中,目前其最新版本是3.1。
Unitils功能特色
java
Unitils模块组件
Unitils经过模块化的方式来组织各个功能模块,采用相似于Spring的模块划分方式,如unitils-core、unitils-database、unitils-mock等。比之前整合在一个工程里面显得更加清晰,目前全部模块以下所示:spring
Unitils的核心架构中包含Moudule和TestListener两个概念,相似Spring中黏连其余开源软件中的FactoryBean概念。能够当作第三方测试工具的一个黏合剂。总体框架如图16-4所示:
经过TestListener能够在测试运行的不一样阶段注入某些功能。同时某一个TestListener又被一个对应的Module所持有。 Unitils也能够当作一个插件体系结构,TestListener在整个Unitils中又充当了插件中扩展点的角色,从TestListener这 个接口中咱们能够看到,它能够在crateTestObject、before(after)Class、 before(after)TestMethod、beforeSetup、afterTeardown的不一样切入点添加不一样的动做。
Unitils配置文件 sql
Unitils的配置定义了通常配置文件的名字unitils.properties和用户自定义配置文件unitils- local.properties,并给出了默认的模块及模块对应的className,便于Unitils加载对应的模块module。可是若是用户分 别在unitils.properties文件及unitils -local.properties文件中对相同属性配置不一样值时,将会以unitils-local.properties 的配置内容为主。
Unitils断言
典型的单元测试通常都包含一个重要的组成部分:对比实际产生的结果和但愿的结果是否一致的方法,即断言方法(assertEquals)。Unitils 为咱们提供了一个很是实用的断言方法,咱们以第2章中编写的用户领域对象User为蓝本,比较两个User对象的实例来开始认识Unitils的断言之 旅。
assertReflectionEquals:反射断言
在Java世界中,要比较现有两个对象实例是否相等,若是类没有重写equals()方法,用两个对象的引用是否一致做为判断依据。有时候,咱们并不须要 关注两个对象是否引用同一个对象,只要两个对象的属性值同样就能够了。在JUnit单元测试中,有两种测试方式进行这样的场景测试:一是在比较实体类中重 写equals()方法,而后进行对象比较;二是把对象实例的属性一个一个进行比较。无论采用哪一种方法,都比较烦锁,Unitils为咱们提供了一种很是 简单的方法,即便用ReflectionAssert.assertReflectionEquals方法, 如代码清单16-11所示: 数据库
ReflectionAssert. AssertReflectionEquals(指望值,实际值,比较级别)方法为咱们提供了各类级别的比较断言。下面咱们依次介绍这些级别的比较断言。
ReflectionComparatorMode.LENIENT_ORDER:忽略要断言集合collection 或者array 中元素的顺序。
ReflectionComparatorMode.IGNORE_DEFAULTS:忽略Java类型默认值,如引用类型为null,整型类型为0,或者布尔类型为false时,那么断言忽略这些值的比较。
ReflectionComparatorMode.LENIENT_DATES:比较两个实例的Date是否是都被设置了值或者都为null,而忽略Date的值是否相等。
assertLenientEquals:断言
ReflectionAssert 类为咱们提供了两种比较断言:既忽略顺序又忽略默认值的断言assertLenientEquals,使用这种断言就能够进行简单比较。下面经过实例学习其具体的用法,如代码清单16-12所示。数组
assertPropertyXxxEquals:属性断言
assertLenientEquals 和assertReflectionEquals 这两个方法是把对象做为总体进行比较,ReflectionAssert 类还给咱们提供了只比较对象特定属性的方法:assertPropertyReflection Equals()和assertPropertyLenientEquals()。下面经过实例学习其具体的用法,如代码清单16-13所示。 session
assertPropertyReflectionEquals()断言是默认严格比较模式可是能够手动设置比较级别的断言,assertPropertyLenientEquals()断言是具备忽略顺序和忽略默认值的断言。
集成Spring
Unitils 提供了一些在Spring 框架下进行单元测试的特性。Spring 的一个基本特性就是,类要设计成为没有Spring 容器或者在其余容器下仍然易于进行单元测试。可是不少时候在Spring 容器下进行测试仍是很是有用的。
Unitils 提供了如下支持 Spring 的特性:架构
ApplicationContext 配置
能够简单地在一个类、方法或者属性上加上@SpringApplicationContext 注解,并用Spring的配置文件做为参数,来加载Spring应用程序上下文。下面咱们经过实例来介绍一下如何建立ApplicationContext。 app
在①-1处,经过@SpringApplicationContext 注解加载baobaotao-service.xml和baobaotao- dao.xml两个配置文件,生成一个Spring应用上下文,咱们就能够在注解的范围内引用applicationContext这个上下文。在①-2 处,经过@SpringBean注解注入当前Spring容器中相应的Bean,如实例中加载ID为“userService”的Bean到当前测试范 围。在①-3处,经过JUnit断言验证是否成功加载applicationContext和userService。Unitils加载Spring上 下文的过程是:首先扫描父类的@SpringApplicationContext注解,若是找到了就在加载子类的配置文件以前加载父类的配置文件,这样 就可让子类重写配置文件和加载特定配置文件。
细心的读者可能会发现,采用这种方式加载Spring应用上下文,每次执行测试时,都会重复加载Spring应用上下文。Unitils为咱们提供在类上加载Spring应用上下文的能力,以免重复加载的问题。 框架
在父类BaseServiceTest里指定了Spring配置文件,Spring应用上下文只会建立一次,而后在子类 SimpleUserServiceTest 里会重用这个应用程序上下文。加载Spring应用上下文是一个很是繁重的操做,若是重用这个Spring应用上下文就会大大提高测试的性能。dom
在①处,使用@SpringBean 注解从Spring容器中加载一个ID为userService的Bean。在②处,使用@ SpringBeanByType注解从Spring容器中加载一个与UserService相同类型的Bean,若是找不到相同类型的Bean,就会抛 出异常。在③处,使用@SpringBeanByName 注解从Spring容器中加载一个与当前属性名称相同的Bean。
集成Hibernate
Hibernate是一个优秀的O / R开源框架,它极大地简化了应用程序的数据访问层开发。虽然咱们在使用一个优秀的O/R框架,但并不意味咱们无须对数据访问层进行单元测试。单元测试仍然 很是重要。它不只能够确保Hibernate映射类的映射正确性,也能够很便捷地测试HQL查询等语句。Unitils为方便测试 Hibernate,提供了许多实用的工具类,如HibernateUnitils就是其中一个,使用 assertMappingWithDatabaseConsistent()方法,就能够方便测试映射文件的正确性。
SessionFactory 配置
能够简单地在一个类、方法或者属性上加上@ HibernateSessionFactory 注解,并用Hibernate的配置文件做为参数,来加载Hibernate上下文。下面咱们经过实例来介绍一下如何建立SessionFactory。
在父类BaseDaoTest里指定了Hibernate配置文件,Hibernate应用上下文只会建立一次,而后在子类 SimpleUserDaoTest里会重用这个应用程序上下文。加载Hibernate应用上下文是一个很是繁重的操做,若是重用这个 Hibernate应用上下文就会大大提高测试的性能。
为了更好演示如何应用Unitils测试基于Hibernate数据访问层,在这个实例中不使用Spring框架。因此在执行测试时,须要先建立相应的数 据访问层实例,如实例中的userDao。其建立过程如①处所示,先手工实例化一个UserDao,而后获取父类中建立的SessionFactory, 并设置到UserDao中。在②处,使用Unitils提供的工具类HibernateUnitils中的方法测试咱们的Hibernate映射文件。在 ③处,经过JUnit的断言验证 UserDao相关方法,看是否与咱们预期的结果一致。
集成Dbunit
Dbunit是一个基于JUnit扩展的数据库测试框架。它提供了大量的类,对数据库相关的操做进行了抽象和封装。Dbunit经过使用用户自定义的数据 集以及相关操做使数据库处于一种可知的状态,从而使得测试自动化、可重复和相对独立。虽然不用Dbunit也能够达到这种目的,可是咱们必须为此付出代价 (编写大量代码、测试及维护)。既然有了这么优秀的开源框架,咱们又何须再造轮子。目前其最新的版本是2.4.8。
随着Unitils的出现,将Spring、Hibernate、DbUnit等整合在一块儿,使得DAO层的单元测试变得很是容易。Unitils采用模 块化方式来整合第三方框架,经过实现扩展模块接口org.unitils.core.Module来实现扩展功能。在Unitils中已经实现一个 DbUnitModule,很好整合了DbUnit。经过这个扩展模块,就能够在Unitils中使用Dbunit强大的数据集功能,如用于准备数据的 @DataSet注解、用于验证数据的@ExpectedDataSet注解。Unitils集成DbUnit流程图如图16-5所示。
16.4.5 自定义扩展模块
Unitils经过模块化的方式来组织各个功能模块,对外提供一个统一的扩展模块接口org.unitils.core.Module来实现与第三方框架 的集成及自定义扩展。在Unitils中已经实现目前一些主流框架的模块扩展,如Spring、Hibernate、DbUnit、Testng等。若是 这些内置的扩展模块没法知足需求,咱们能够实现本身的一些扩展模块。扩展Unitils模块很简单,如代码清单16-19所示。
在①处新建自定义扩展模块CustomExtModule,实现Module接口。在②处新建自定义监听模块,继承TestListener。在 ③处重写(@Override)TestListener里的相关方法,完成相关扩展的功能。实现自定义扩展模块以后,剩下的工做就是在Unitils配 置文件unitils.properties中注册这个自定义扩展的模块:
http://stamen.iteye.com/blog/1480316