EasyMock使用说明

来自官网的使用说明,原文见http://www.easymock.org/EasyMock2_0_Documentation.html

1.1. 准备

大多数的软件系统都不是单独运行的,它们都需要于其他部分系统合作,来完成工作。大多数情况下,我们在进行单元测试时,不会担心其他部分,而是假定它们都会工作良好。如果我们需要考虑其他部分的情况,Mock对象可以帮助我们对某一单元,进行隔离测试。Mock对象将在测试中代替合作者。

下边的例子是一个Collaborator接口:

package org.easymock.samples;

public interface Collaborator {

void documentAdded(String title);

void documentChanged(String title);

void documentRemoved(String title);

byte voteForRemoval(String title);

byte[] voteForRemovals(String[] title);

}

实现了这个接口的类(在这里都是监听器),是一个叫做ClassUnderTest类的合作者:

public class ClassUnderTest {

//...

public void addListener(Collaborator listener) {

//...

}

public void addDocument(String title, byte[] document) {

//...

}

public boolean removeDocument(String title) {

//...

}

public boolean removeDocuments(String[] titles) {

//...

}

}

这些代码都可以在easymock.zip的sample.zip中找到,包名为org.easymock.samples

下面的例子假设你熟悉JUnit测试框架。虽然这些测试使用了JUnit 3.8.1,你也可以使用JUnit 4或TestNG

1.2. 第一个Mock对象

我们现在就要写一个测试用例,然后根据它来了解EasyMock包的结构。samples.zip里包含了这个测试的修改版。我们的第一个测试,应该检测,一个不存在的document的removal操作是否会告诉那些合作者。这里的测试,没有定义Mock对象:

package org.easymock.samples;

import junit.framework.TestCase;

public class ExampleTest extends TestCase {

private ClassUnderTest classUnderTest;

private Collaborator mock;

protected void setUp() {

classUnderTest = new ClassUnderTest();

classUnderTest.addListener(mock);

}

public void testRemoveNonExistingDocument() {

// This call should not lead to any notification

// of the Mock Object:

classUnderTest.removeDocument("Does not exist");

}

}

对于大多数使用EasyMock 2的测试,我们只要使用静态导入org.easymock.EasyMock的所有方法。这是EasyMock 2中唯一没有内在方法,也没有废弃方法的类。

import static org.easymock.EasyMock.*;

import junit.framewok.TestCase;

public class ExampleTest extends TestCase {

private ClassUnderTest classUnderTest;

private Collaborator mock;

}

为了获得Mock对象,我们需要

  • 为我们想使用的接口,创建一个Mock对象。
  • 录制预期的行为,然后
  • 将Mock对象转换到replay(重放)状态

这里有一个小例子:

protected void setUp() {

mock = createMock(Collaborator.class); // 1

classUnderTest = new ClassUnderTest();

classUnderTest.addListener(mock);

}

public void testRemoveNonExistingDocument() {

// 2 (we do not expect anything)

replay(mock); // 3

classUnderTest.removeDocument("Does not exist");

}

完成第三步后,mock是一个Collaborator接口的Mock对象,它不希望有任何的调用。这意味着,如果我们改变了ClassUnderTest,调用了接口的任何一个方法,Mock对象就回抛出一个AssertionError:

java.lang.AssertionError:

Unexpected method call documentRemoved("Does not exist"):

at org.easymock.internal.MockInvocationHandler.invoke(MockInvocationHandler.java:29)

at org.easymock.internal.ObjectMethodsFilter.invoke(ObjectMethodsFilter.java:44)

at $Proxy0.documentRemoved(Unknown Source)

at org.easymock.samples.ClassUnderTest.notifyListenersDocumentRemoved(ClassUnderTest.java:74)

at org.easymock.samples.ClassUnderTest.removeDocument(ClassUnderTest.java:33)

at org.easymock.samples.ExampleTest.testRemoveNonExistingDocument(ExampleTest.java:24)

...

1.3. 添加行为

让我们开始写第二个测试。如果一个document添加到ClassUnderTest中,我们希望mock.documentAdded()会被调用,并把document的标题作为参数。

public void testAddDocument() {

mock.documentAdded("New Document"); // 2

replay(mock); // 3

classUnderTest.addDocument("New Document", new byte[0]);

}

在录制环节(调用replay之前),Mock对象没有办法像Mock对象那样工作,但是它记录了方法调用。在调用replay之后,它就可以使用了。检查是否出现了对期望的方法的调用。

如果ClassUnderTest.addDocument("New Document", new byte[0])调用了预期的方法,但使用了错误参数,Mock对象会抛出一个AssertionErro:

java.lang.AssertionError:

Unexpected method call documentAdded("Wrong title"):

documentAdded("New Document"): expected: 1, actual: 0

at org.easymock.internal.MockInvocationHandler.invoke(MockInvocationHandler.java:29)

at org.easymock.internal.ObjectMethodsFilter.invoke(ObjectMethodsFilter.java:44)

at $Proxy0.documentAdded(Unknown Source)

at org.easymock.samples.ClassUnderTest.notifyListenersDocumentAdded(ClassUnderTest.java:61)

at org.easymock.samples.ClassUnderTest.addDocument(ClassUnderTest.java:28)

at org.easymock.samples.ExampleTest.testAddDocument(ExampleTest.java:30)

...

没有出现的所有预期记录都会表现出来。会把不是预期的调用做完全的比较(这个例子里没有出现)。如果方法调用次数过多,Mock对象也会抱怨:

java.lang.AssertionError:

Unexpected method call documentAdded("New Document"):

documentAdded("New Document"): expected: 1, actual: 1 (+1)

at org.easymock.internal.MockInvocationHandler.invoke(MockInvocationHandler.java:29)

at org.easymock.internal.ObjectMethodsFilter.invoke(ObjectMethodsFilter.java:44)

at $Proxy0.documentAdded(Unknown Source)

at org.easymock.samples.ClassUnderTest.notifyListenersDocumentAdded(ClassUnderTest.java:62)

at org.easymock.samples.ClassUnderTest.addDocument(ClassUnderTest.java:29)

at org.easymock.samples.ExampleTest.testAddDocument(ExampleTest.java:30)

...

1.4. 验证行为

这里有一个我们一直没有处理的问题:如果我们指定一个行为,我们应该验证它是否确实使用了。刚才的测试会在Mock对象没有调用的时候通过,为了严整指定的行为是否使用,我们需要调用verify(mock)。

public void testAddDocument() {

mock.documentAdded("New Document"); // 2

replay(mock); // 3

classUnderTest.addDocument("New Document", new byte[0]);

verify(mock);

}

如果Mock中的方法没有调用,我们会得到下面的异常:

java.lang.AssertionError:

Expectation failure on verify:

documentAdded("New Document"): expected: 1, actual: 0

at org.easymock.internal.MocksControl.verify(MocksControl.java:70)

at org.easymock.EasyMock.verify(EasyMock.java:536)

at org.easymock.samples.ExampleTest.testAddDocument(ExampleTest.java:31)

...

异常信息包括了所有没有运行的期望。

1.5. 期待对方法调用特定次数

到现在为止。我们的测试都只考虑单一方法调用。下一个测试需要测试,有一个已经存在的document添加的时候,是否会引起mock.documentChanged()方法,并使用适当的参数。为了确认。我们检测三次(只是作为例子而已:))。

public void testAddAndChangeDocument() {

mock.documentAdded("Document");

mock.documentChanged("Document");

mock.documentChanged("Document");

mock.documentChanged("Document");

mock.documentChanged("Document");

replay(mock);

classUnderTest.addDocument("Document", new byte[0]);

classUnderTest.addDocument("Document", new byte[0]);

classUnderTest.addDocument("Document", new byte[0]);

classUnderTest.addDocument("Document", new byte[0]);

verify(mock);

}

为了避免重复输入mock.documentChanged("Document"),EasyMock提供了一个捷径。我们在expectLastCall()后边使用times(int times)方法,指定调用的次数。代码如下:

public void testAddAndChangeDocument() {

mock.documentAdded("Document");

mock.documentChanged("Document");

expectLastCall().times(3);

replay(mock);

classUnderTest.addDocument("Document", new byte[0]);

classUnderTest.addDocument("Document", new byte[0]);

classUnderTest.addDocument("Document", new byte[0]);

classUnderTest.addDocument("Document", new byte[0]);

verify(mock);

}

如果方法调用了太多次,我们会获得一个异常,告诉我们方法调用了过多次。在第一个方法调用超过次数的时候,就会立即产生错误。

java.lang.AssertionError:

Unexpected method call documentChanged("Document"):

documentChanged("Document"): expected: 3, actual: 3 (+1)

at org.easymock.internal.MockInvocationHandler.invoke(MockInvocationHandler.java:29)

at org.easymock.internal.ObjectMethodsFilter.invoke(ObjectMethodsFilter.java:44)

at $Proxy0.documentChanged(Unknown Source)

at org.easymock.samples.ClassUnderTest.notifyListenersDocumentChanged(ClassUnderTest.java:67)

at org.easymock.samples.ClassUnderTest.addDocument(ClassUnderTest.java:26)

at org.easymock.samples.ExampleTest.testAddAndChangeDocument(ExampleTest.java:43)

如果调用次数比预期少,verify(mock)就会抛出一个AssertionError:

java.lang.AssertionError:

Expectation failure on verify:

documentChanged("Document"): expected: 3, actual: 2

at org.easymock.internal.MocksControl.verify(MocksControl.java:70)

at org.easymock.EasyMock.verify(EasyMock.java:536)

at org.easymock.samples.ExampleTest.testAddAndChangeDocument(ExampleTest.java:43)

...

1.6. 指定返回值

为了指定返回值,我们在expect(T value)中封装了预期的调用,在它返回的对象中,使用andReturn(Object returnValue)指定了返回值。

作为例子,我们检测删除document的流程。如果ClassUnderTest得到了一个删除document的调用。它会询问所有的合作者的表决,来调用byte voteForRemoval(String title)来进行删除。正的返回值表示同意删除。如果所有值的和是正数,就删除document并调用所有合作者的documentRemoved(String title):

public void testVoteForRemoval() {

mock.documentAdded("Document"); // expect document addition

// expect to be asked to vote for document removal, and vote for it

expect(mock.voteForRemoval("Document")).addReturn((byte) 42);

mock.documentRemoved("Document"); // expect document removal

replay(mock);

classUnderTest.addDocument("Document", new byte[0]);

assertTrue(classUnderTest.removeDocument("Document"));

verify(mock);

}

public void testVoteAgainstRemoval() {

mock.documentAdded("Document"); // expect document addition

// expect to be asked to vote for document removal, and vote against it

expect(mock.voteForRemoval("Document")).andReturn((byte) -42);

replay(mock);

classUnderTest.addDocument("Document", new byte[0]);

assertFalse(classUnderTest.removeDocument("Document"));

verify(mock);

}

返回值的类型,会在编译阶段检查。作为例子,下边的代码无法通过编译,因为提供的返回值与方法的返回值不匹配:

expect(mock.voteForRemoval("Document")).andReturn("wrong type");

1.7. 不使用expect(T value)获得为对象设置的返回值,我们可以使用expectLastCall

EasyMock使用说明

时间: 2024-10-11 21:18:56

EasyMock使用说明的相关文章

EASYMOCK 使用说明

EasyMock 是一套用于通过简单的方法对于给定的接口生成 Mock 对象的类库.它提供对接口的模拟,能够通过录制.回放.检查三步来完成大体的测试过程,可以验证方法的调用种类.次数.顺序,可以令 Mock 对象返回指定的值或抛出指定异常.通过 EasyMock,我们可以方便的构造 Mock 对象从而使单元测试顺利进行. 根据指定的接口或类,EasyMock 能够动态的创建 Mock 对象(EasyMock 默认只支持为接口生成 Mock 对象,如果需要为类生成 Mock 对象,在 EasyMo

Linux系统下安装rz/sz命令及使用说明

对于经常使用Linux系统的人员来说,少不了将本地的文件上传到服务器或者从服务器上下载文件到本地,rz / sz命令很方便的帮我们实现了这个功能,但是很多Linux系统初始并没有这两个命令.今天,我们就简单的讲解一下如何安装和使用rz.sz命令. 1.软件安装 (1)编译安装 root 账号登陆后,依次执行以下命令: 1 cd /tmp 2 wget http://www.ohse.de/uwe/releases/lrzsz-0.12.20.tar.gz 3 tar zxvf lrzsz-0.1

android 布局之滑动探究 scrollTo 和 scrollBy 方法使用说明

涉及到滑动,就涉及到VIEW,大家都知道,android的UI界面都是由一个一个的View以及View的派生类组成,View作为基类,而常用的布局里面的各种布局就是它派生出来的ViewGroup的子类,ViewGroup作为各个组件的容器搭建了整体的UI.以下是android UI的结构示示意图: 查看源码 /** * Implement this to do your drawing. * * @param canvas the canvas on which the background w

Git使用说明

Git是流行的分布式版本控制系统,可以方便的管理多人协作的项目并避免了集中式版本控制系统对服务器的依赖. 简介 版本库(repository)是一个由Git管理的目录,Git将跟踪工作目录下文件的修改并在需要时还原. 在工作目录下.git子目录则维护着版本库 . Git维护三个组件: 工作目录: 保存实际文件 暂存区 : 保存尚未提交的修改 版本库: 保存已提交的修改 HEAD: 指向最后一次提交后的结果(checkout 命令的主要功能就是操作HEAD). Git将每次提交的修改串成一条时间线

软件使用说明

软件使用说明:我们的软件是一款基于在校女大学生的记账软件,根据调查身边的女生,统计出了大部分的女生每个月开销的分类.在我们的软件中按这些分类记录每个人的每天的开销,根据调查结果显示有部分学生还有收入,所以我们的记账软件还增加了收入项.我们软件可以根据你每天输入的开销来计算你每个月的开销,并且你可以在其中设置每个月开销的额度,根据你的开销对你的花销进行提醒.在每天你也可以收到关于你这一天开销的提醒,比如:提醒你录入,提醒你今天的花费是否超标.

IDEA工具使用说明

IDEA使用说明 1.安装 2.开始界面 1)create New Project (新建项目) 2)Import Project  (导入项目) 3)Open (打开已有的项目) 4)Check out from Version Control (从版本控制库中导入项目) 3.新建项目 1)方式一: 说明:左边的列表显示的是IDEA可以的项支持目种类,右边是需要额外添加的构面,选择好相应的构面,点击next. 说明:上面的一部分是制定项目的名称,下面一部分是制定项目中模块的名称.当创建了一个项

中海达RTK使用说明之两个点计算参数

中海达RTK求转换参数操作步骤,中海达GPS四参数计算,中海达HI-Survey参数计算简要操作,已知两个控制点求转换参数, 手薄型号:Ihand20 安卓系统手薄 软件:hi-survey road\elec 仪器:中海达公司任意RTK产品 使用两个点求转换参数流程: 第一步:碎步测量控制点 第二步:把两个控制点已知坐标输入到控制点库 第三步:计算参数 第四步:检核参数精度,测控制点作对比,或点放样控制点 使用两个点如何求转换参数? 如何选取控制点计算参数? 四参数控制范围只是计算选用的两个控

AC6102开发板USB3.0测试和使用说明

AC6102开发板USB3.0测试和使用说明 概述 AC6102上集成了一颗Cypress 推出的高性能USB3.0传输芯片CYUSB3014,Cypress称之为EZ-USBFX3.该芯片性能强劲,功能强大,接口简单,非常适合用于各种需要高速数据传输的场合,以下为摘自EZ-USBFX3数据手册中关于该芯片的介绍: 赛普拉斯EZ-USBFX3是新一代USB3.0外设控制器,具有高度集成的灵活特性,可帮助开发人员为任何系统添加USB3.0功能.EZ-USBFX3具有一个可进行完全配置的并行通用可编

Mallet 使用说明

Mallet:自然语言处理工具包 发表于128 天前 ? 技术, 科研 ? 评论数 6 ? 被围观 1006 Views+ MALLET是基于java的自然语言处理工具箱,包括分档得分类.句类.主题模型.信息抽取等其他机器学习在文本方面的应用,虽然是文本的应用,但是完全可以拿到多媒体方面来,例如机器视觉. MALLET包含了足够的文本分类的算法,还有特征提取的算法等.文本分类的算法像是Na?ve Bayes, Maximum Entropy, and Decision Trees等,而且也对代码