您好,欢迎访问三七文档
当前位置:首页 > 中学教育 > 初中教育 > Unitils单元测试介绍
Unitils教程Unitils概述Spring的测试框架为我们提供一个强大的测试环境,解决日常单元测试中遇到的大部分测试难题:如运行多个测试用例和测试方法时,Spring上下文只需创建一次;数据库现场不受破坏;方便手工指定Spring配置文件、手工设定Spring容器是否需要重新加载等。但也存在不足的地方,基本上所有的Java应用都涉及数据库,带数据库应用系统的测试难点在于数据库测试数据的准备、维护、验证及清理。Spring测试框架并不能很好地解决所有问题。要解决这些问题,必须整合多方资源,如DbUnit、Unitils、Mokito等。其中Unitils正是这样的一个测试框架。Unitils测试框架目的是让单元测试变得更加容易和可维护。Unitils构建在DbUnit与EasyMock项目之上并与JUnit和TestNG相结合。支持数据库测试,支持利用Mock对象进行测试并提供与Spring和Hibernate相集成。Unitils设计成以一种高度可配置和松散耦合的方式来添加这些服务到单元测试中,目前其最新版本是3.1。Unitils功能特点自动维护和强制关闭单元测试数据库(支持Oracle、Hsqldb、MySQL、DB2)。简化单元测试数据库连接的设置。简化利用DbUnit测试数据的插入。简化Hibernatesession管理。自动测试与数据库相映射的Hibernate映射对象。易于把Spring管理的Bean注入到单元测试中,支持在单元测试中使用Spring容器中的HibernateSessionFactory。简化EasyMockMock对象创建。简化Mock对象注入,利用反射等式匹配EasyMock参数。Unitils模块组件Unitils通过模块化的方式来组织各个功能模块,采用类似于Spring的模块划分方式,如unitils-core、unitils-database、unitils-mock等。比以前整合在一个工程里面显得更加清晰,目前所有模块如下所示:unitils-core:核心内核包。unitils-database:维护测试数据库及连接池。unitils-DbUnit:使用DbUnit来管理测试数据。unitils-easymock:支持创建Mock和宽松的反射参数匹配。unitils-inject:支持在一个对象中注入另一个对象。unitils-mock:整合各种Mock,在Mock的使用语法上进行了简化。unitils-orm:支持Hibernate、JPA的配置和自动数据库映射检查。unitils-spring:支持加载Spring的上下文配置,并检索和SpringBean注入。Unitils的核心架构中包含Moudule和TestListener两个概念,类似Spring中黏连其他开源软件中的FactoryBean概念。可以看成第三方测试工具的一个黏合剂。整体框架如下图所示:Unitils配置文件unitils-defaults.properties:默认配置文件,开启所有功能。unitils.properties:项目级配置文件,用于项目通用属性配置。unitils-local.properties:用户级配置文件,用于个人特殊属性配置。Unitils的配置定义了一般配置文件的名字unitils.properties和用户自定义配置文件unitils-local.properties,并给出了默认的模块及模块对应的className,便于Unitils加载对应的模块module。但是如果用户分别在unitils.properties文件及unitils-local.properties文件中对相同属性配置不同值时,将会以unitils-local.properties的配置内容为主。Assertionutilities断言应用应用反射的断言典型的单体测试一般都包含一个重要的组成部分:对比实际产生的结果和希望的结果是否一致的方法:断言方法(assertEquals)。Unitils为我们提供了一个非常实用的assertion方法,让我们用比较两个USER对象的实例(User包括id,firstname,lastname属性)来开始我们这一部分的介绍。publicclassUser{privatelongid;privateStringfirst;privateStringlast;publicUser(longid,Stringfirst,Stringlast){this.id=id;this.first=first;this.last=last;}}Useruser1=newUser(1,John,Doe);Useruser2=newUser(1,John,Doe);assertEquals(user1,user2);因为两个user包含相同的属性,所以你一定以为断言是成功的。但是事实恰恰相反,断言失败,因为user类没有覆写equals()方法,所以断言就用判断两个对象是否相等来来返回结果,换句话说就是采用了user1==user2的结果,用两个对象的引用是否一致作为判断的依据。假如你像下面这样重写equals方法,publicbooleanequals(Objectobject){if(objectinstanceofUser){returnid==((User)object).id;}returnfalse;}也许通过判断两个USER的ID是否相等来判断这两个user是否相等在您的程序逻辑里是行得通的,但是在单体测试里未必是有意义的,因为判断两个user是否相等被简化成了user的id是否相等了。Useruser1=newUser(1,John,Doe);Useruser2=newUser(1,Jane,Smith);assertEquals(user1,user2);按照上面的代码逻辑,也许断言成功了,但是这是您期望的么?所以最好避免使用equals()方法来实现两个对象的比较(除非对象的属性都是基本类型)。对了,还有一个办法也许能够有效,那就是把对象的属性一个一个的比较。Useruser1=newUser(1,John,Doe);Useruser2=newUser(1,John,Doe);assertEquals(user1.getId(),user2.getId());assertEquals(user1.getFirst(),user2.getFirst());assertEquals(user1.getLast(),user2.getLast());Unitils其实为我们提供了非常简单的方法,一种采用反射的方法。使用ReflectionAssert.assertReflectionEquals方法,上面的代码可以重写如下:Useruser1=newUser(1,John,Doe);Useruser2=newUser(1,John,Doe);assertReflectionEquals(user1,user2);这种断言采用反射机制,循环的比较两个对象的filed的值,比如上面的例子,它就是依次对比id,first,last的值是否相等。如果某个filed本身就是object,那么断言会递归的依次比对这两个object的所有filed,对于Arrays,Maps,collection也是一样的,会通过反射机制递归的比较所有的element,如果值的类型是基本类型(int,long,...)或者基本类型的包装类(Integer,Long,...),就会比较值是否相等(using==)。看看下面的代码,这回断言成功了!assertReflectionEquals(1,1L);ListDoublemyList=newArrayListDouble();myList.add(1.0);myList.add(2.0);assertReflectionEquals(Arrays.asList(1,2),myList);宽松式断言源于对代码可维护性的原因,只添加对测试有益的断言是十分重要的。让我用一个例子来说明这一点:假如一个计算accountbalance的测试代码,那么就没有对bank-customer的name进行断言的必要,因为这样就增加了测试代码的复杂度,让人难于理解,更重要的是当代码发生变化时增加了测试代码的脆弱性。为了让你的测试代码更容易的适应其他代码的重构,那么一定保证你的断言和测试数据是建立在测试范围之内的。为了帮助我们写出这样的测试代码,ReflectionAssert方法为我们提供了各种级别的宽松断言。下面我们依次介绍这些级别的宽松断言。顺序是宽松的:第一种宽松级别就是忽略collection或者array中元素的顺序。其实我们在应用list的时候往往对元素的顺序是不关心的。比如:一个代码想要搜索出所有无效的银行账号,那么返回的结果的顺序就对我们业务逻辑没什么影响。为了实现这种宽松模式,ReflectionAssert.assertReflectionEquals方法可以通过配置来实现对顺序的忽略,只要ReflectionAssert.assertReflectionEquals方法设置ReflectionComparatorMode.LENIENT_ORDER参数就可以了。比如:ListIntegermyList=Arrays.asList(3,2,1);assertReflectionEquals(Arrays.asList(1,2,3),myList,LENIENT_ORDER);忽略缺省值第二种宽松方式是:如果断言方法被设置为ReflectionComparatorMode.IGNORE_DEFAULTS模式的话,java的defaultvalues比如objects是null值是0或者false,那么断言忽略这些值的比较,换句话说就是断言只会比较那些你初始化了的期望值,如果你没有初始化一些filed,那么断言就不会去比较它们。还是拿个例子说明比较好,假设有一个user类:有firstname,lastname,street...field属性,但是你只想比较两个对象实例的firstname和street的值,其他的属性值你并不关心,那么就可以像下面这么比较了。UseractualUser=newUser(John,Doe,newAddress(Firststreet,12,Brussels));UserexpectedUser=newUser(John,null,newAddress(Firststreet,null,null));assertReflectionEquals(expectedUser,actualUser,IGNORE_DEFAULTS);你想忽略的属性值设置为null那么一定把它放到左边参数位置(=expected),如果只有右边参数的值为null,那么断言仍然会比较的。assertReflectionEquals(null,anyObject,IGNORE_DEFAULTS);//SucceedsassertReflectionEquals(anyObject,null,IGNORE_DEFAULTS);//Fails宽松的date第三种宽松模式是ReflectionComparatorMode.LENIENT_DATES,这种模式只会比较两个实例的date是不是都被设置了值或者都为null,而忽略date的值是否相等,如果你想严格比较对象的每一个域,而又不想去比较时间的值是不是相等,那么这种模式就是合适你的。DateactualDate=newDate(44444);DateexpectedDate=newDate();assertReflectionEquals(expectedDate,actualDate,LENIENT_DATES);assertLeni
本文标题:Unitils单元测试介绍
链接地址:https://www.777doc.com/doc-3401334 .html