EasyMock简单使用方法
2009-11-15 15:26
375 查看
EasyMock 是一套通过简单的方法对于指定的接口或类生成 Mock 对象的类库,它能利用对接口或类的模拟来辅助单元测试。本文将对 EasyMock 的功能和原理进行介绍,并通过示例来说明如何使用 EasyMock 进行单元测试。
Mock 方法是单元测试中常见的一种技术,它的主要作用是模拟一些在应用中不容易构造或者比较复杂的对象,从而把测试与测试边界以外的对象隔离开。
编写自定义的 Mock 对象需要额外的编码工作,同时也可能引入错误。EasyMock 提供了根据指定接口动态构建 Mock
对象的方法,避免了手工编写 Mock 对象。本文将向您展示如何使用 EasyMock 进行单元测试,并对 EasyMock 的原理进行分析。
1.Mock 对象与 EasyMock 简介
单元测试与 Mock 方法
单元测试是对应用中的某一个模块的功能进行验证。在单元测试中,我们常遇到的问题是应用中其它的协同模块尚未开发完成,或者被测试模块需要和一些不
容易构造、比较复杂的对象进行交互。另外,由于不能肯定其它模块的正确性,我们也无法确定测试中发现的问题是由哪个模块引起的。
Mock 对象能够模拟其它协同模块的行为,被测试模块通过与 Mock 对象协作,可以获得一个孤立的测试环境。此外,使用 Mock
对象还可以模拟在应用中不容易构造(如 HttpServletRequest 必须在 Servlet 容器中才能构造出来)和比较复杂的对象(如
JDBC 中的 ResultSet 对象),从而使测试顺利进行。
EasyMock 简介
手动的构造 Mock 对象会给开发人员带来额外的编码量,而且这些为创建 Mock
对象而编写的代码很有可能引入错误。目前,有许多开源项目对动态构建 Mock
对象提供了支持,这些项目能够根据现有的接口或类动态生成,这样不仅能避免额外的编码工作,同时也降低了引入错误的可能。
EasyMock 是一套用于通过简单的方法对于给定的接口生成 Mock
对象的类库。它提供对接口的模拟,能够通过录制、回放、检查三步来完成大体的测试过程,可以验证方法的调用种类、次数、顺序,可以令 Mock
对象返回指定的值或抛出指定异常。通过 EasyMock,我们可以方便的构造 Mock 对象从而使单元测试顺利进行。
安装 EasyMock
EasyMock 是采用 MIT license 的一个开源项目,您可以在 Sourceforge 上下载到相关的 zip
文件。目前您可以下载的 EasyMock 最新版本是2.3,它需要运行在 Java 5.0 平台上。如果您的应用运行在 Java 1.3 或
1.4 平台上,您可以选择 EasyMock1.2。在解压缩 zip 包后,您可以找到 easymock.jar 这个文件。如果您使用
Eclipse 作为 IDE,把 easymock.jar 添加到项目的 Libraries
里就可以使用了(如下图所示)。此外,由于我们的测试用例运行在 JUnit 环境中,因此您还需要 JUnit.jar(版本3.8.1以上)。
图1:Eclipse 项目中的 Libraries
2.使用 EasyMock 进行单元测试
通过 EasyMock,我们可以为指定的接口动态的创建 Mock 对象,并利用 Mock 对象来模拟协同模块或是领域对象,从而使单元测试顺利进行。这个过程大致可以划分为以下几个步骤:
使用 EasyMock 生成 Mock 对象;
设定 Mock 对象的预期行为和输出;
将 Mock 对象切换到 Replay 状态;
调用 Mock 对象方法进行单元测试;
对 Mock 对象的行为进行验证。
接下来,我们将对以上的几个步骤逐一进行说明。除了以上的基本步骤外,EasyMock 还对特殊的 Mock 对象类型、特定的参数匹配方式等功能提供了支持,我们将在之后的章节中进行说明。
使用 EasyMock 生成 Mock 对象
根据指定的接口或类,EasyMock 能够动态的创建 Mock 对象(EasyMock 默认只支持为接口生成 Mock 对象,如果需要为类生成 Mock 对象,在 EasyMock 的主页上有扩展包可以实现此功能),我们以
接口为例说明EasyMock的功能。
是每一个 Java 开发人员都非常熟悉的接口:
清单1:ResultSet 接口
通常,构建一个真实的
对象需要经过一个复杂的过程:在开发过程中,开发人员通常会编写一个
类来获取数据库连接
,并利用
创建一个
。执行一个
可以获取到一个或多个
对象。这样的构造过程复杂并且依赖于数据库的正确运行。数据库或是数据库交互模块出现问题,都会影响单元测试的结果。
我们可以使用 EasyMock 动态构建
接口的 Mock 对象来解决这个问题。一些简单的测试用例只需要一个 Mock 对象,这时,我们可以用以下的方法来创建 Mock 对象:
其中
是
类所提供的静态方法,你可以通过 static import 将其引入(注:static import 是 java 5.0 所提供的新特性)。
如果需要在相对复杂的测试用例中使用多个 Mock 对象,EasyMock 提供了另外一种生成和管理 Mock 对象的机制:
类的
方法能创建一个接口
的对象,该对象能创建并管理多个 Mock 对象。如果需要在测试中使用多个 Mock 对象,我们推荐您使用这一机制,因为它在多个 Mock 对象的管理上提供了相对便捷的方法。
如果您要模拟的是一个具体类而非接口,那么您需要下载扩展包 EasyMock Class Extension 2.2.2。在对具体类进行模拟时,您只要用
类中的静态方法代替
类中的静态方法即可。
设定 Mock 对象的预期行为和输出
在一个完整的测试过程中,一个 Mock 对象将会经历两个状态:Record 状态和 Replay 状态。Mock
对象一经创建,它的状态就被置为 Record。在 Record 状态,用户可以设定 Mock
对象的预期行为和输出,这些对象行为被录制下来,保存在 Mock 对象中。
添加 Mock 对象行为的过程通常可以分为以下3步:
对 Mock 对象的特定方法作出调用;
通过
提供的静态方法
获取上一次方法调用所对应的 IExpectationSetters 实例;
通过
实例设定 Mock 对象的预期输出。
设定预期返回值
Mock 对象的行为可以简单的理解为 Mock 对象方法的调用和方法调用所产生的输出。在 EasyMock 2.3 中,对 Mock 对象行为的添加和设置是通过接口
来实现的。Mock 对象方法的调用可能产生两种类型的输出:(1)产生返回值;(2)抛出异常。接口
提供了多种设定预期输出的方法,其中和设定返回值相对应的是 andReturn 方法:
我们仍然用
接口的 Mock 对象为例,如果希望方法
的返回值为 "My return value",那么你可以使用以下的语句:
以上的语句表示
的
方法被调用一次,这次调用的返回值是 "My return value"。有时,我们希望某个方法的调用总是返回一个相同的值,为了避免每次调用都为 Mock 对象的行为进行一次设定,我们可以用设置默认返回值的方法:
假设我们创建了
和
接口的 Mock 对象 mockStatement 和 mockResultSet,在测试过程中,我们希望 mockStatement 对象的
方法总是返回 mockResultSet,我们可以使用如下的语句
EasyMock 在对参数值进行匹配时,默认采用
方法。因此,如果我们以
作为参数,预期方法将不会被调用。如果您希望上例中的 SQL 语句能不区分大小写,可以用特殊的参数匹配器来解决这个问题,我们将在 "在 EasyMock 中使用参数匹配器" 一章对此进行说明。
设定预期异常抛出
对象行为的预期输出除了可能是返回值外,还有可能是抛出异常。
提供了设定预期抛出异常的方法:
和设定默认返回值类似,
接口也提供了设定抛出默认异常的函数:
设定预期方法调用次数
通过以上的函数,您可以对 Mock 对象特定行为的预期输出进行设定。除了对预期输出进行设定,
接口还允许用户对方法的调用次数作出限制。在
所提供的这一类方法中,常用的一种是
方法:
该方法可以 Mock 对象方法的调用次数进行确切的设定。假设我们希望 mockResultSet 的
方法在测试过程中被调用3次,期间的返回值都是 "My return value",我们可以用如下语句:
注意到
和
方法的返回值依然是一个
实例,因此我们可以在此基础上继续调用
方法。
除了设定确定的调用次数,
还提供了另外几种设定非准确调用次数的方法:
:该方法最少被调用 minTimes 次,最多被调用 maxTimes 次。
:该方法至少被调用一次。
:该方法可以被调用任意次。
某些方法的返回值类型是 void,对于这一类方法,我们无需设定返回值,只要设置调用次数就可以了。以
接口的
方法为例,假设在测试过程中,该方法被调用3至5次:
为了简化书写,EasyMock 还提供了另一种设定 Mock 对象行为的语句模式。对于上例,您还可以将它写成:
这个语句和上例中的语句功能是完全相同的。
将 Mock 对象切换到 Replay 状态
在生成 Mock 对象和设定 Mock 对象行为两个阶段,Mock 对象的状态都是 Record 。在这个阶段,Mock 对象会记录用户对预期行为和输出的设定。
在使用 Mock 对象进行实际的测试前,我们需要将 Mock 对象的状态切换为 Replay。在 Replay 状态,Mock
对象能够根据设定对特定的方法调用作出预期的响应。将 Mock 对象切换成 Replay 状态有两种方式,您需要根据 Mock
对象的生成方式进行选择。如果 Mock 对象是通过
类提供的静态方法 createMock 生成的(第1节中介绍的第一种 Mock 对象生成方法),那么
类提供了相应的 replay 方法用于将 Mock 对象切换为 Replay 状态:
如果 Mock 对象是通过
接口提供的
方法生成的(第1节中介绍的第二种Mock对象生成方法),那么您依旧可以通过
接口对它所创建的所有 Mock 对象进行切换:
以上的语句能将在第1节中生成的 mockConnection、mockStatement 和 mockResultSet 等3个 Mock 对象都切换成 Replay 状态。
调用 Mock 对象方法进行单元测试
为了更好的说明 EasyMock 的功能,我们引入 src.zip 中的示例来解释 Mock
对象在实际测试阶段的作用。其中所有的示例代码都可以在 src.zip 中找到。如果您使用的 IDE 是 Eclipse,在导入 src.zip
之后您可以看到 Workspace 中增加的 project(如下图所示)。
图2:导入 src.zip 后的 Workspace
下面是示例代码中的一个接口
,它的实现类
的主要功能是从数据库中读取一个 Sales Order 的 Region 和 Total Price,并根据读取的数据计算该 Sales Order 的 Price Level(完整的实现代码都可以在 src.zip 中找到):
清单2:SalesOrder 接口
其实现类
中对
的实现如下:
清单3:SalesOrderImpl 实现
方法
读取了
对象包含的数据。当我们将之前定义的 Mock 对象调整为 Replay 状态,并将该对象作为参数传入,那么 Mock 对象的方法将会返回预先定义的预期返回值。完整的 TestCase 如下:
清单4:完整的TestCase
在这个示例中,我们首先创建了
的 Mock 对象 moResultSet,并记录该 Mock 对象的预期行为。之后我们调用了
,将 Mock 对象的状态置为 Replay 状态。在实际的测试阶段,Sales Order 对象的
方法调用了 mockResultSet 对象的
和
方法读取 mockResultSet 中的数据。Sales Order 对象根据读取的数据计算出 Price Level,并和预期输出进行比较。
对 Mock 对象的行为进行验证
在利用 Mock 对象进行实际的测试过程之后,我们还有一件事情没有做:对 Mock 对象的方法调用的次数进行验证。
为了验证指定的方法调用真的完成了,我们需要调用
方法进行验证。和
方法类似,您需要根据 Mock 对象的生成方式来选用不同的验证方式。如果 Mock 对象是由
类提供的
静态方法生成的,那么我们同样采用
类的静态方法
进行验证:
如果Mock对象是有
接口所提供的
方法生成的,那么采用该接口提供的
方法,例如第1节中的
实例 control:
将对 control 实例所生成的 Mock 对象 mockConnection、mockStatement 和 mockResultSet 等进行验证。如果将上例中
的预期次数修改为2,在 Eclipse 中将可以看到:
图3:Mock对象验证失败
Mock 对象的重用
为了避免生成过多的 Mock 对象,EasyMock 允许对原有 Mock 对象进行重用。要对 Mock 对象重新初始化,我们可以采用
reset 方法。和 replay 和 verify 方法类似,EasyMock 提供了两种 reset 方式:(1)如果 Mock 对象是由
类中的静态方法
生成的,那么该 Mock 对象的可以用
类的静态方法
重新初始化;(2)如果 Mock 方法是由
实例的
方法生成的,那么该
实例方法
的调用将会把所有该实例创建的 Mock 对象重新初始化。
在重新初始化之后,Mock 对象的状态将被置为 Record 状态。
Mock 方法是单元测试中常见的一种技术,它的主要作用是模拟一些在应用中不容易构造或者比较复杂的对象,从而把测试与测试边界以外的对象隔离开。
编写自定义的 Mock 对象需要额外的编码工作,同时也可能引入错误。EasyMock 提供了根据指定接口动态构建 Mock
对象的方法,避免了手工编写 Mock 对象。本文将向您展示如何使用 EasyMock 进行单元测试,并对 EasyMock 的原理进行分析。
1.Mock 对象与 EasyMock 简介
单元测试与 Mock 方法
单元测试是对应用中的某一个模块的功能进行验证。在单元测试中,我们常遇到的问题是应用中其它的协同模块尚未开发完成,或者被测试模块需要和一些不
容易构造、比较复杂的对象进行交互。另外,由于不能肯定其它模块的正确性,我们也无法确定测试中发现的问题是由哪个模块引起的。
Mock 对象能够模拟其它协同模块的行为,被测试模块通过与 Mock 对象协作,可以获得一个孤立的测试环境。此外,使用 Mock
对象还可以模拟在应用中不容易构造(如 HttpServletRequest 必须在 Servlet 容器中才能构造出来)和比较复杂的对象(如
JDBC 中的 ResultSet 对象),从而使测试顺利进行。
EasyMock 简介
手动的构造 Mock 对象会给开发人员带来额外的编码量,而且这些为创建 Mock
对象而编写的代码很有可能引入错误。目前,有许多开源项目对动态构建 Mock
对象提供了支持,这些项目能够根据现有的接口或类动态生成,这样不仅能避免额外的编码工作,同时也降低了引入错误的可能。
EasyMock 是一套用于通过简单的方法对于给定的接口生成 Mock
对象的类库。它提供对接口的模拟,能够通过录制、回放、检查三步来完成大体的测试过程,可以验证方法的调用种类、次数、顺序,可以令 Mock
对象返回指定的值或抛出指定异常。通过 EasyMock,我们可以方便的构造 Mock 对象从而使单元测试顺利进行。
安装 EasyMock
EasyMock 是采用 MIT license 的一个开源项目,您可以在 Sourceforge 上下载到相关的 zip
文件。目前您可以下载的 EasyMock 最新版本是2.3,它需要运行在 Java 5.0 平台上。如果您的应用运行在 Java 1.3 或
1.4 平台上,您可以选择 EasyMock1.2。在解压缩 zip 包后,您可以找到 easymock.jar 这个文件。如果您使用
Eclipse 作为 IDE,把 easymock.jar 添加到项目的 Libraries
里就可以使用了(如下图所示)。此外,由于我们的测试用例运行在 JUnit 环境中,因此您还需要 JUnit.jar(版本3.8.1以上)。
图1:Eclipse 项目中的 Libraries
|
通过 EasyMock,我们可以为指定的接口动态的创建 Mock 对象,并利用 Mock 对象来模拟协同模块或是领域对象,从而使单元测试顺利进行。这个过程大致可以划分为以下几个步骤:
使用 EasyMock 生成 Mock 对象;
设定 Mock 对象的预期行为和输出;
将 Mock 对象切换到 Replay 状态;
调用 Mock 对象方法进行单元测试;
对 Mock 对象的行为进行验证。
接下来,我们将对以上的几个步骤逐一进行说明。除了以上的基本步骤外,EasyMock 还对特殊的 Mock 对象类型、特定的参数匹配方式等功能提供了支持,我们将在之后的章节中进行说明。
使用 EasyMock 生成 Mock 对象
根据指定的接口或类,EasyMock 能够动态的创建 Mock 对象(EasyMock 默认只支持为接口生成 Mock 对象,如果需要为类生成 Mock 对象,在 EasyMock 的主页上有扩展包可以实现此功能),我们以
ResultSet
接口为例说明EasyMock的功能。
java.sql.ResultSet
是每一个 Java 开发人员都非常熟悉的接口:
清单1:ResultSet 接口
public interface java.sql.ResultSet { ...... public abstract java.lang.String getString(int arg0) throws java.sql.SQLException; public abstract double getDouble(int arg0) throws java.sql.SQLException; ...... } |
RecordSet
对象需要经过一个复杂的过程:在开发过程中,开发人员通常会编写一个
DBUtility
类来获取数据库连接
Connection
,并利用
Connection
创建一个
Statement
。执行一个
Statement
可以获取到一个或多个
ResultSet
对象。这样的构造过程复杂并且依赖于数据库的正确运行。数据库或是数据库交互模块出现问题,都会影响单元测试的结果。
我们可以使用 EasyMock 动态构建
ResultSet
接口的 Mock 对象来解决这个问题。一些简单的测试用例只需要一个 Mock 对象,这时,我们可以用以下的方法来创建 Mock 对象:
ResultSet mockResultSet = createMock(ResultSet.class); |
createMock
是
org.easymock.EasyMock
类所提供的静态方法,你可以通过 static import 将其引入(注:static import 是 java 5.0 所提供的新特性)。
如果需要在相对复杂的测试用例中使用多个 Mock 对象,EasyMock 提供了另外一种生成和管理 Mock 对象的机制:
IMocksControl control = EasyMock.createControl(); java.sql.Connection mockConnection = control.createMock(Connection.class); java.sql.Statement mockStatement = control.createMock(Statement.class); java.sql.ResultSet mockResultSet = control.createMock(ResultSet.class); |
EasyMock
类的
createControl
方法能创建一个接口
IMocksControl
的对象,该对象能创建并管理多个 Mock 对象。如果需要在测试中使用多个 Mock 对象,我们推荐您使用这一机制,因为它在多个 Mock 对象的管理上提供了相对便捷的方法。
如果您要模拟的是一个具体类而非接口,那么您需要下载扩展包 EasyMock Class Extension 2.2.2。在对具体类进行模拟时,您只要用
org.easymock.classextension.EasyMock
类中的静态方法代替
org.easymock.EasyMock
类中的静态方法即可。
设定 Mock 对象的预期行为和输出
在一个完整的测试过程中,一个 Mock 对象将会经历两个状态:Record 状态和 Replay 状态。Mock
对象一经创建,它的状态就被置为 Record。在 Record 状态,用户可以设定 Mock
对象的预期行为和输出,这些对象行为被录制下来,保存在 Mock 对象中。
添加 Mock 对象行为的过程通常可以分为以下3步:
对 Mock 对象的特定方法作出调用;
通过
org.easymock.EasyMock
提供的静态方法
expectLastCall
获取上一次方法调用所对应的 IExpectationSetters 实例;
通过
IExpectationSetters
实例设定 Mock 对象的预期输出。
设定预期返回值
Mock 对象的行为可以简单的理解为 Mock 对象方法的调用和方法调用所产生的输出。在 EasyMock 2.3 中,对 Mock 对象行为的添加和设置是通过接口
IExpectationSetters
来实现的。Mock 对象方法的调用可能产生两种类型的输出:(1)产生返回值;(2)抛出异常。接口
IExpectationSetters
提供了多种设定预期输出的方法,其中和设定返回值相对应的是 andReturn 方法:
IExpectationSetters<T> andReturn(T value); |
ResultSet
接口的 Mock 对象为例,如果希望方法
mockResult.getString(1)
的返回值为 "My return value",那么你可以使用以下的语句:
mockResultSet.getString(1); expectLastCall().andReturn("My return value"); |
mockResultSet
的
getString
方法被调用一次,这次调用的返回值是 "My return value"。有时,我们希望某个方法的调用总是返回一个相同的值,为了避免每次调用都为 Mock 对象的行为进行一次设定,我们可以用设置默认返回值的方法:
void andStubReturn(Object value); |
Statement
和
ResultSet
接口的 Mock 对象 mockStatement 和 mockResultSet,在测试过程中,我们希望 mockStatement 对象的
executeQuery
方法总是返回 mockResultSet,我们可以使用如下的语句
mockStatement.executeQuery("SELECT * FROM sales_order_table"); expectLastCall().andStubReturn(mockResultSet); |
Object.equals()
方法。因此,如果我们以
"select * from sales_order_table"
作为参数,预期方法将不会被调用。如果您希望上例中的 SQL 语句能不区分大小写,可以用特殊的参数匹配器来解决这个问题,我们将在 "在 EasyMock 中使用参数匹配器" 一章对此进行说明。
设定预期异常抛出
对象行为的预期输出除了可能是返回值外,还有可能是抛出异常。
IExpectationSetters
提供了设定预期抛出异常的方法:
IExpectationSetters<T> andThrow(Throwable throwable); |
IExpectationSetters
接口也提供了设定抛出默认异常的函数:
void andStubThrow(Throwable throwable); |
通过以上的函数,您可以对 Mock 对象特定行为的预期输出进行设定。除了对预期输出进行设定,
IExpectationSetters
接口还允许用户对方法的调用次数作出限制。在
IExpectationSetters
所提供的这一类方法中,常用的一种是
times
方法:
IExpectationSetters<T>times(int count); |
getString
方法在测试过程中被调用3次,期间的返回值都是 "My return value",我们可以用如下语句:
mockResultSet.getString(1); expectLastCall().andReturn("My return value").times(3); |
andReturn
和
andThrow
方法的返回值依然是一个
IExpectationSetters
实例,因此我们可以在此基础上继续调用
times
方法。
除了设定确定的调用次数,
IExpectationSetters
还提供了另外几种设定非准确调用次数的方法:
times(int minTimes, int maxTimes)
:该方法最少被调用 minTimes 次,最多被调用 maxTimes 次。
atLeastOnce()
:该方法至少被调用一次。
anyTimes()
:该方法可以被调用任意次。
某些方法的返回值类型是 void,对于这一类方法,我们无需设定返回值,只要设置调用次数就可以了。以
ResultSet
接口的
close
方法为例,假设在测试过程中,该方法被调用3至5次:
mockResultSet.close(); expectLastCall().times(3, 5); |
expect(mockResult.close()).times(3, 5); |
将 Mock 对象切换到 Replay 状态
在生成 Mock 对象和设定 Mock 对象行为两个阶段,Mock 对象的状态都是 Record 。在这个阶段,Mock 对象会记录用户对预期行为和输出的设定。
在使用 Mock 对象进行实际的测试前,我们需要将 Mock 对象的状态切换为 Replay。在 Replay 状态,Mock
对象能够根据设定对特定的方法调用作出预期的响应。将 Mock 对象切换成 Replay 状态有两种方式,您需要根据 Mock
对象的生成方式进行选择。如果 Mock 对象是通过
org.easymock.EasyMock
类提供的静态方法 createMock 生成的(第1节中介绍的第一种 Mock 对象生成方法),那么
EasyMock
类提供了相应的 replay 方法用于将 Mock 对象切换为 Replay 状态:
replay(mockResultSet); |
IMocksControl
接口提供的
createMock
方法生成的(第1节中介绍的第二种Mock对象生成方法),那么您依旧可以通过
IMocksControl
接口对它所创建的所有 Mock 对象进行切换:
control.replay(); |
调用 Mock 对象方法进行单元测试
为了更好的说明 EasyMock 的功能,我们引入 src.zip 中的示例来解释 Mock
对象在实际测试阶段的作用。其中所有的示例代码都可以在 src.zip 中找到。如果您使用的 IDE 是 Eclipse,在导入 src.zip
之后您可以看到 Workspace 中增加的 project(如下图所示)。
图2:导入 src.zip 后的 Workspace
下面是示例代码中的一个接口
SalesOrder
,它的实现类
SalesOrderImpl
的主要功能是从数据库中读取一个 Sales Order 的 Region 和 Total Price,并根据读取的数据计算该 Sales Order 的 Price Level(完整的实现代码都可以在 src.zip 中找到):
清单2:SalesOrder 接口
public interface SalesOrder |
SalesOrderImpl
中对
loadDataFromDB
的实现如下:
清单3:SalesOrderImpl 实现
public class SalesOrderImpl implements SalesOrder |
loadDataFromDB
读取了
ResultSet
对象包含的数据。当我们将之前定义的 Mock 对象调整为 Replay 状态,并将该对象作为参数传入,那么 Mock 对象的方法将会返回预先定义的预期返回值。完整的 TestCase 如下:
清单4:完整的TestCase
public class SalesOrderTestCase extends TestCase { public void testSalesOrder() { IMocksControl control = EasyMock.createControl(); ...... ResultSet mockResultSet = control.createMock(ResultSet.class); try { ...... mockResultSet.next(); expectLastCall().andReturn(true).times(3); expectLastCall().andReturn(false).times(1); mockResultSet.getString(1); expectLastCall().andReturn("DEMO_ORDER_001").times(1); expectLastCall().andReturn("DEMO_ORDER_002").times(1); expectLastCall().andReturn("DEMO_ORDER_003").times(1); mockResultSet.getString(2); expectLastCall().andReturn("Asia Pacific").times(1); expectLastCall().andReturn("Europe").times(1); expectLastCall().andReturn("America").times(1); mockResultSet.getDouble(3); expectLastCall().andReturn(350.0).times(1); expectLastCall().andReturn(1350.0).times(1); expectLastCall().andReturn(5350.0).times(1); control.replay(); ...... int i = 0; String[] priceLevels = { "Level_A", "Level_C", "Level_E" }; while (mockResultSet.next()) { SalesOrder order = new SalesOrderImpl(); order.loadDataFromDB(mockResultSet); assertEquals(order.getPriceLevel(), priceLevels[i]); i++; } control.verify(); } catch (Exception e) { e.printStackTrace(); } } } |
ResultSet
的 Mock 对象 moResultSet,并记录该 Mock 对象的预期行为。之后我们调用了
control.replay()
,将 Mock 对象的状态置为 Replay 状态。在实际的测试阶段,Sales Order 对象的
loadDataFromDB
方法调用了 mockResultSet 对象的
getString
和
getDouble
方法读取 mockResultSet 中的数据。Sales Order 对象根据读取的数据计算出 Price Level,并和预期输出进行比较。
对 Mock 对象的行为进行验证
在利用 Mock 对象进行实际的测试过程之后,我们还有一件事情没有做:对 Mock 对象的方法调用的次数进行验证。
为了验证指定的方法调用真的完成了,我们需要调用
verify
方法进行验证。和
replay
方法类似,您需要根据 Mock 对象的生成方式来选用不同的验证方式。如果 Mock 对象是由
org.easymock.EasyMock
类提供的
createMock
静态方法生成的,那么我们同样采用
EasyMock
类的静态方法
verify
进行验证:
verify(mockResultSet); |
IMocksControl
接口所提供的
createMock
方法生成的,那么采用该接口提供的
verify
方法,例如第1节中的
IMocksControl
实例 control:
control.verify(); |
expectLastCall().andReturn(false).times(1)
的预期次数修改为2,在 Eclipse 中将可以看到:
图3:Mock对象验证失败
Mock 对象的重用
为了避免生成过多的 Mock 对象,EasyMock 允许对原有 Mock 对象进行重用。要对 Mock 对象重新初始化,我们可以采用
reset 方法。和 replay 和 verify 方法类似,EasyMock 提供了两种 reset 方式:(1)如果 Mock 对象是由
org.easymock.EasyMock
类中的静态方法
createMock
生成的,那么该 Mock 对象的可以用
EasyMock
类的静态方法
reset
重新初始化;(2)如果 Mock 方法是由
IMocksControl
实例的
createMock
方法生成的,那么该
IMocksControl
实例方法
reset
的调用将会把所有该实例创建的 Mock 对象重新初始化。
在重新初始化之后,Mock 对象的状态将被置为 Record 状态。
相关文章推荐
- 5分钟学会-最简单的MyBatis使用方法
- 压力测试之badboy和Jmeter的简单使用方法
- 使用each方法实现简单的下拉列表联动
- CentOS的简单使用之配置编译MySQL( 版本号:mysql-community-5.7.18-1.el7.src.rpm,主要参考官网方法)
- EasyMock 使用方法与原理剖析
- awk基本使用方法简单介绍
- 使用.NET REACTOR使用方法,制作软件许可证,做一个简单的许可证系统步骤
- hashlib 简单使用方法
- Mybatis分页插件PageHelper的配置和简单使用方法(推荐)
- sphinx使用及其简单配置方法
- Android使用OpenCV和FFMpeg的简单方法-开源项目javacv的使用
- 在Linux命令行终端中使用python的简单方法(推荐)
- AndroidSlidingUpPanel 使用控制和简单的分析方法
- Qt只QStringList的简单使用方法
- 使用WinRar将Qt编译生成的exe和依赖的dll文件打包为一个exe文件的简单方法
- Jmeter对HTTP请求压力测试、并发测试的简单使用方法,详解
- 使用MyBatis Generator自动创建代码(最简单方法)
- 关于asyncbox插件open方法的简单使用
- extern外部方法使用C#简单样例
- javascript Promise简单学习使用方法小结