您好,欢迎访问三七文档
当前位置:首页 > 中学教育 > 初中教育 > 单元测试系列讲座(1)-Junit+Easymock
1Junit+Easymockdrawedoutbyhongliang.chen2内容提要单元测试简介单元测试的好处Mock对象与EasyMock简介使用EasyMock进行单元测试本次讲座小结。3单元测试简介•单元测试是一个独立的工作单元,是对应用中的某一个模块(module)的功能进行验证。•在JAVA应用程序中“独立的一个单元”常指一个方法。一个工作单元是一项任务,它不依赖于其它的任何任务的完成。•单元测试所关注的常常是方法是否满足API契约(对应用编程接口API的一种看法,把它看作是调用者和被调用者之间的正式协定)。4单元测试的好处•单元测试可以帮助您在开发过程中验证和优化设计。•单元测试可以降低不确定性从而降低风险。•单元测试用例可以当作文档使用。•单元测试有利于后期可能会进行的回归测试。•单元测试便于日常开发流程的维护。当把一天的工作任务准备提交到VSS上时,只需要运行当天所有的测试用例,确保全部通过了之后再提交,这样就能保证编写代码的正确性。5Mock对象与EasyMock简介•单元测试与Mock方法-单元测试是对应用中的某一个模块的功能进行验证。在单元测试中,我们常遇到的问题是应用中其它的协同模块尚未开发完成,或者被测试模块需要和一些不容易构造、比较复杂的对象进行交互。另外,由于不能肯定其它模块的正确性,我们也无法确定测试中发现的问题是由哪个模块引起的。-Mock对象能够模拟其它协同模块的行为,被测试模块通过与Mock对象协作,可以获得一个孤立的测试环境。此外,使用Mock对象还可以模拟在应用中不容易构造(如HttpServletRequest必须在Servlet容器中才能构造出来)和比较复杂的对象(如JDBC中的ResultSet对象),从而使测试顺利进行。6安装EasyMock-EasyMock是采用MITlicense的一个开源项目,您可以在Sourceforge上下载到相关的zip文件。目前您可以下载的EasyMock最新版本是2.3,它需要运行在Java5.0平台上。如果您的应用运行在Java1.3或1.4平台上,您可以选择EasyMock1.2。在解压缩zip包后,您可以找到easymock.jar这个文件。如果您使用Eclipse作为IDE,把easymock.jar添加到项目的Libraries里就可以使用了(如下图所示)。此外,由于我们的测试用例运行在JUnit环境中,因此您还需要JUnit.jar(版本3.8.1以上)。7下图是Eclipse中项目TestMockProj的Libraries8使用EasyMock进行单元测试通过EasyMock,我们可以为指定的接口动态的创建Mock对象,并利用Mock对象来模拟协同模块或是领域对象,从而使单元测试顺利进行。这个过程大致可以划分为以下几个步骤:-使用EasyMock生成Mock对象-设定Mock对象的预期行为和输出-将Mock对象切换到Replay状态-调用Mock对象方法进行单元测试-对Mock对象的行为进行验证。接下来,我们将对以上的几个步骤逐一进行说明。9使用EasyMock生成Mock对象-根据指定的接口或类,EasyMock能够动态的创建Mock对(EasyMock默认只支持为接口生成Mock对象,如果需要为类生成Mock对象,在EasyMock的主页上有扩展包可以实现此功能),我们以MyListener接口为例说明EasyMock的功能。清单1,接口MyListener:publicinterfaceMyListener{voiddocumentAdded(Stringtitle);voiddocumentChanged(Stringtitle);voiddocumentRemoved(Stringtitle);bytevoteForRemoval(Stringtitle);bytevoteForRemovals(String[]title);}10通常,构建一个真实的RecordSet对象需要经过一个复杂的过程:在开发过程中,开发人员通常会编写一个DBUtility类来获取数据库连接Connection,并利用Connection创建一个Statement。执行一个Statement可以获取到一个或多个ResultSet对象。这样的构造过程复杂并且依赖于数据库的正确运行。数据库或是数据库交互模块出现问题,都会影响单元测试的结果。我们可以使用EasyMock动态构建MyListener接口的Mock对象来解决这个问题。一些简单的测试用例只需要一个Mock对象,这时,我们可以用以下的方法来创建Mock对象:11MyListenermock=createMock(MyListener.class);其中createMock是org.easymock.EasyMock类所提供的静态方法,你可以通过staticimport将其引入(注:staticimport是java5.0所提供的新特性)。如果需要在相对复杂的测试用例中使用多个Mock对象,EasyMock提供了另外一种生成和管理Mock对象的机制:IMocksControlcontrol=EasyMock.createControl();java.sql.ConnectionmockConnection=control.createMock(Connection.class);java.sql.StatementmockStatement=control.createMock(Statement.class);MyListenermock=control.createMock(MyListener.class);12EasyMock类的createControl方法能创建一个接口IMocksControl的对象,该对象能创建并管理多个Mock对象。如果需要在测试中使用多个Mock对象,我们推荐您使用这一机制,因为它在多个Mock对象的管理上提供了相对便捷的方法。如果您要模拟的是一个具体类而非接口,那么您需要下载扩展包EasyMockClassExtension2.2.2。在对具体类进行模拟时,您只要用org.easymock.classextension.EasyMock类中的静态方法代替org.easymock.EasyMock类中的静态方法即可。13•设定Mock对象的预期行为和输出添加Mock对象行为的过程通常可以分为以下3步:1)、对Mock对象的特定方法作出调用2)、通过org.easymock.EasyMock提供的静态方expectLastCall获取上一次方法调用所对应的IExpectationSetters实例3)、通过IExpectationSetters实例设定Mock对象的预期输出。14-设定预期返回值Mock对象的行为可以简单的理解为Mock对象方法的调用和方法调用所产生的输出。在EasyMock2.3版中,对Mock对象行为的添加和设置是通过接口IExpectationSetters来实现的。Mock对象方法的调用可能产生两种类型的输出:(1)、产生返回值;(2)、抛出异常。接口IExpectationSetters提供了多种设定预期输出的方法,其中和设定返回值相对应的是andReturn方法:IExpectationSettersTandReturn(Tvalue);15我们仍然用MyListener接口的Mock对象为例,如果希望方法MyListener.voteForRemoval()能够删除标题为“Ducument”的文件投票,并且返回值为42,那么你可以使用以下的语句:expect(mock.voteForRemoval(“Document”)).andReturn((byte)42);以上的语句表示mock的voteForRemoval方法被调用一次,这次调用的返回值是42。有时,我们希望某个方法的调用总是返回一个相同的值,为了避免每次调用都为Mock对象的行为进行一次设定,我们可以用设置默认返回值的方法:voidandStubReturn(Objectvalue);16-设定预期异常抛出对象行为的预期输出除了可能是返回值外,还有可能是抛出异常。EasyMock提供了设定预期抛出异常的方法:IExpectationSettersTandThrow(Throwablethrowable);和设定默认返回值类似,EasyMock也提供了设定抛出默认异常的函数:voidandStubThrow(Throwablethrowable);17-设定预期方法调用次数通过以上的函数,您可以对Mock对象特定行为的预期输出进行设定。除了对预期输出进行设定,EasyMock还允许用户对方法的调用次数作出限制,常用的是times方法:IExpectationSettersTtimes(intcount);假设我们要把MyListen接口的documentChanged方法调用三次,可以这样:mock.documentAdded(Document);mock.documentChanged(Document);expectLastCall().times(3);也可以简写为:expect(mock.documentChanged(Document)).time(3);18除了设定确定的调用次数,EasyMock还提供了另外几种设定非准确调用次数的方法:times(intminTimes,intmaxTimes):该方法最少被调用minTimes次,最多被调用maxTimes次。atLeastOnce():该方法至少被调用一次。anyTimes():该方法可以被调用任意次。某些方法的返回值类型是void,对于这一类方法,我们无需设定返回值,只要设置调用次数就可以了。以MyListener接口的documentChanged方法为例,假设在测试过程中,该方法被调用3至5次:mock.documentAdded(Document);mock.documentChanged(Document);expectLastCall().times(3,5);19•将Mock对象切换到Replay状态-在生成Mock对象和设定Mock对象行为两个阶段,Mock对象的状态都是Record。在这个阶段,Mock对象会记录用户对预期行为和输出的设定。-在使用Mock对象进行实际的测试前,我们需要将Mock对象的状态切换为Replay。在Replay状态,Mock对象能够根据设定对特定的方法调用作出预期的响应。将Mock对象切换成Replay状态有两种方式,您需要根据Mock对象的生成方式进行选择。如果Mock对象是通过org.easymock.EasyMock类提供的静态方法createMock生成的,那么EasyMock类提供了相应的replay方法用于将Mock对象切换为Replay状态:replay(mock)20-如果Mock对象是通过IMocksControl接口提供的createMock方法生成的(前面介绍的第二种Mock对象生成方法),那么您依旧可以通过IMocksControl接口对它所创建的所有Mock对象进行切换:control.replay();以上的语句能将前面生成的mockConnection、mockStatement和mockMyListener等3个Mock对象都切换成Replay状态。21•调用Mock对象方法进行单元测试为更好的说明EasyMock的功能,我们引入TestMockProj示例来解释Mock对象在实际测试阶段的作用。其中所有的示例代码都可以在TestMockProj中找到。如果您使用的IDE是Eclipse,在导入TestMockProj工程之后您可以看到Workspace中增加的project(如下图所示)。•22在Eclipse中导入TestMockProj工程文件之后,可以直接查看代码详细清
本文标题:单元测试系列讲座(1)-Junit+Easymock
链接地址:https://www.777doc.com/doc-4137907 .html