EasyMock使用手记
from:http://www.blogjava.net/supercrsky/articles/162766.html
Mock 对象能够模拟领域对象的部分行为,并且能够检验运行结果是否和预期的一致。领域类将通过与 Mock 对象的交互,来获得一个独立的测试环境(引自《 精通 Spring——Java 轻量级架构开发实践 》。
在模仿对象中,我们定义了四个概念:
1 )目标对象:正在测试的对象
2 )合作者对象:由目标对象创建或获取的对象
3 )模仿对象:遵循模仿对象模式的合作者的子类(或实现)
4 )特殊化对象:覆盖创建方法以返回模仿对象而不是合作者的目标的子类
一般来说,应用模仿对象的过程如下:
1 )创建模仿对象的实例
2 )设置模仿对象中的状态和期望值
3 )将模仿对象作为参数来调用域代码
4 )验证模仿对象中的一致性
那么,我们应该如何以及在哪里使用 Mock 对象呢?一般来说,对于目标对象中的合作者对象,在测试时如果其状态或行为的实现严重地依赖外部资源(比如数据持久化中的 DAO ,比如负责发送电子邮件的类),或者团队并行开发时,目标对象的合作者对象并没有实现(比如 J2EE 中,横向分工时,负责 Action 的调用 Service ,负责 Service 调用 DAO 时,相应的 Service 及 DAO 没有实现),这时我们就需要模仿这些类。其实,在做J2EE 时,传统的 N 层架构中,我们都是面向接口编程的,我们定义了 DAO 接口,我们定义了 Service 接口,这样做的优点就是我们在测试时可以构造实现接口的 Mock 类。这里不得不提依赖注入,通过依赖注入,我们才能在测试时 set Mock 对象。这也说明,为了方便测试,我们不得不一步一步 重构代码,而模式就在重构中自然地产生了。
对于 Mock 对象,我们可以根据 合作者接口(或者是类) 实现具体的 Mock 类,这样的 Mock 类实际上是Stub 。有些情况下, Stub 是必要的。但对于诸如 DAO 、 Service ,我们只关心在给定参数的情况下,调用的方法能够返回预期的值,我们根本不关心其内部实现,这时候如果使用 Stub 的话就会产生不必要的代码。我们需要的就是能 动态地生成 Mock 对象而不需要编写它们的工具, EasyMock 就是这样的工具。
EasyMock 是一个 Mock 对象的类库,现在的版本是 2.0 ,这个版本只支持 Mock 接口,如果需要 Mock 类,需要下载它的扩展包。
下面通过一个具体的例子说明一下 Mock 对象的使用,我写的例子就是测试 Service 类中的一个方法, Mock的对象是 DAO 。
首先是一个简单的实体 bean Account:
package easymocktest.domain;
import org.apache.commons.lang.builder.ToStringBuilder;
import org.apache.commons.lang.builder.ToStringStyle;
public class Account {
private Long id;
private String name;
private String pwd;
public Long getId() {
return id;
}
public void setId(Long id) {
this .id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this .name = name;
}
public String getPwd() {
return pwd;
}
public void setPwd(String pwd) {
this .pwd = pwd;
}
/**
* @see java.lang.Object#toString()
*/
public String toString() {
return new ToStringBuilder( this , ToStringStyle.MULTI_LINE_STYLE)
.append( " name " , this .name).append( " pwd " , this .pwd).append( " id " ,
this .id).toString();
}
} 
一个只含一个方法的 DAO AccountDAO:
package easymocktest.dao;
import easymocktest.domain. * ;
public interface AccountDAO {
public Account getByNameAndPwd(String name,String pwd);
} 
一个同样只含一个方法的 AccountService 接口:
package easymocktest.service;
import easymocktest.domain. * ;
public interface AccountService {
public Account getAccount(String name,String pwd);
} 
与 AccountService 相应的实现类:
package easymocktest.service.impl;
import easymocktest.service.AccountService;
import easymocktest.dao. * ;
import easymocktest.domain.Account;
public class AccountServiceImpl implements AccountService {
private AccountDAO accountDAO;
public AccountDAO getAccountDAO() {
return accountDAO;
}
public void setAccountDAO(AccountDAO accountDAO) {
this .accountDAO = accountDAO;
}
public Account getAccount(String name, String pwd) {
return this .accountDAO.getByNameAndPwd(name, pwd);
}
} 
这里我没有实现 AccountDAO 接口,对于 Mock 测试来说,这也是不需要的。下面就是 AccountServiceImpl 的测试类AccountServiceTest :
package easymocktest.service;
import junit.framework. * ;
import easymocktest.dao. * ;
import easymocktest.domain. * ;
import easymocktest.service.impl. * ;
import static org.easymock.EasyMock.createMock;
import static org.easymock.EasyMock.replay;
import static org.easymock.EasyMock.reset;
import static org.easymock.EasyMock.verify;
import static org.easymock.EasyMock.expect;
public class AccountServiceTest extends TestCase {
private AccountDAO accountDAOMock;
private AccountServiceImpl accountService;
@Override
protected void setUp() throws Exception {
accountDAOMock = createMock(AccountDAO. class );
accountService = new AccountServiceImpl();
accountService.setAccountDAO(accountDAOMock);
}
public void testGetAccount() {
String name = " kafka " ;
String pwd = " 0102 " ;
Account a = new Account();
a.setName(name);
a.setPwd(pwd);
a.setId( new Long( 10 ));
reset(accountDAOMock); // (a)
expect(accountDAOMock.getByNameAndPwd(name, pwd)).andReturn(a); // (b)
replay(accountDAOMock); // (c)
Account b = accountService.getAccount(name, pwd);
assertEquals(a, b);
verify(accountDAOMock); // (d)
}
} 
下面简要的说明一下 Mock 对象的工作过程:
1 )在 setUp() 中,通过 “accountDAOMock = createMock(AccountDAO.class);” (这里使用了 java5 中的静态导入),创建AccountDAO 的 Mock 对象,由于 EasyMock 采用了范型技术,故创建的 Mock 对象不需要强制类型转换。然后通过“accountService.setAccountDAO(accountDAOMock);” 设置目标对象的合作者对象。
2 )对于测试方法 “testGetAccount()” , (a) 处的 reset() 方法是将 Mock 对象复位,也就是重新设置 Mock 对象的状态和行为。由于此处是第一次调用 Mock 对象,可以不必使用 reset() 方法。
3 ) (b) 处 expect() 是录制 Mock 对象方法的调用,其参数就是 Mock 对象的方法,其中如果调用的方法有返回值,要通过andReturn() 方法设置预期的返回值。
4 ) (c) 处的 replay() 是结束录制过程。 在调用 replay() 方法之前的状态, EashMock 称之为 “record 状态 ” 。该状态下, Mock 对象不具备行为(即模拟接口的实现),它仅仅记录方法的调用。在调用 replay() 后,它才以 Mock 对象预期的行为进行工作,检查预期的方法调用是否真的完成。
5 ) (d) 处的 verify() 是用于在录制和回放两个步骤完成之后进行预期和实际结果的检查。这里就是检查 accountDAOMock 是否如预期一样调用了 getByNameAndPwd 方法。
对于上面的举例,它可能并不具有实际的价值,这里我只想抛砖引玉。在 N 层架构的 Java 程序中, Mock对象在单元测试中正发挥着越来越重要的作用。我现在看到的是,在 Service 层与 Web 层, Mock 对象能很好的被应用。有人觉得在 Persistence 层也应该使用 Mock 对象,但就像我们所知道的,在使用 Hibernate 、Ibatis 等 ORM 工具的情况下,我们的 Persistence 层的测试主要测试的就是那些配置文件、查询语句等(实际上是集成测试),如果还 Mock 的话,就失去了测试的意义。
对于 Mock 的更多的信息,你可以访问Mock Objects,在本文写作的过程中,参考了使用模仿对象进行单元测试
等文章,一并感谢。
EasyMock使用手记的更多相关文章
- uni-app官方教程学习手记
本人微信公众号:前端修炼之路,欢迎关注 背景介绍 大概在今年的十月份左右,我了解到Dcloud推出了uni-app.当时下载了一个Hbuilder X,下载了官方提供的hello示例教程.经过一番努力 ...
- Linux.NET实战手记—自己动手改泥鳅(上)
各位读者大家好,不知各位读者有否阅读在下的前一个系列<Linux.NET 学习手记>,在前一个系列中,我们从Linux中Mono的编译安装开始,到Jexus服务器的介绍,以及如何在Linu ...
- Linux.NET学习手记(7)
前一篇中,我们简单的讲述了下如何在Linux.NET中部署第一个ASP.NET MVC 5.0的程序.而目前微软已经提出OWIN并致力于发展VNext,接下来系列中,我们将会向OWIN方向转战. 早在 ...
- Linux.NET学习手记(8)
上一回合中,我们讲解了Linux.NET面对OWIN需要做出的准备,以及介绍了如何将两个支持OWIN协议的框架:SignalR以及NancyFX以OwinHost的方式部署到Linux.NET当中.这 ...
- 关于《Linux.NET学习手记(8)》的补充说明
早前的一两天<Linux.NET学习手记(8)>发布了,这一篇主要是讲述OWIN框架与OwinHost之间如何根据OWIN协议进行通信构成一套完整的系统.文中我们还直接学习如何直接操作OW ...
- U3D DrawCall优化手记
在最近,使用U3D开发的游戏核心部分功能即将完成,中间由于各种历史原因,导致项目存在比较大的问题,这些问题在最后,恐怕只能通过一次彻底的重构来解决 现在的游戏跑起来会有接近130-170个左右的Dra ...
- 信息系统实践手记5-CACHE设计一例
说明:信息系统实践手记系列是系笔者在平时研发中先后遇到的大小的问题,也许朴实和细微,但往往却是经常遇到的问题.笔者对其中比较典型的加以收集,描述,归纳和分享. 摘要:此文描述了笔者接触过的部分信息系统 ...
- 信息系统实践手记6-JS调用Flex的性能问题一例
说明:信息系统实践手记系列是系笔者在平时研发中先后遇到的大小的问题,也许朴实和细微,但往往却是经常遇到的问题.笔者对其中比较典型的加以收集,描述,归纳和分享. 摘要:此文描述了笔者接触过的部分信息系统 ...
- 测试--easymock的使用
使用场景:对于调用其它类中的方法,但是还没有编写完,使用easymock进行单元测试,它提供这些没有编写完的代码期待的默认值. 使用步骤: step1: pom引入: <dependency&g ...
随机推荐
- mouseevent tips
关于roll_over 和 mouse_over的区别,这篇文章说明的很清楚,http://zengrong.net/post/1105.htm 全文如下: 在MouseEvent中,ROLL_OVE ...
- 【转】bash调试经验
原文网址:http://blog.csdn.net/yfkiss/article/details/8636758 bash是Unix/Linux操作系统最常用的shell之一,它非常灵活,和awk.c ...
- 一条sql导致数据库整体性能下降的诊断和解决的全过程
今天早上一来,数据库load就比往常高了许多.想想数据库唯一的变化是昨天早上我曾经重新分析过数据库对象. [@more@] 发现数据库load很高,首先看top发现没有特别异常的进程,在数据库中适时抓 ...
- Cannot run program "/home/mohemi/Program/adt-bundle-linux-x86_64-20130729/sdk//tools/emulator": error=2, 没有那个文件或目录
在64位的Ubuntu下,安装ADT64位的,打开android模拟器出现以下报错: Starting emulator for AVD 'Android' Failed to start emula ...
- C# Datatable的Select方法
lubiaopan 原文 Datatable的Select()方法简介 DataTable是我们在进行开发时经常用到的一个类,并且经常需要对DataTable中的数据进行筛选等操作,下面就介绍一下Da ...
- 常用的Oracle数据库语句 (待更新完毕)
一.常用的查询语句 1.1 常用查询 查表中有多少个字段 select count(*) from user_tab_columns where table_name=upper('表名') 或者 s ...
- 第二个UI脚本--Python+selenium之unittest+HTMLtestRunner及python的继承
前面有一篇对于常见元素的识别和操作的python自动化脚本,这一篇就接着聊下python的类继承,已经它的第三款unittest框架,和报告收集包HTMLtestRunner的应用. 还是直接上代码吧 ...
- 类 .xml
pre{ line-height:1; color:#1e1e1e; background-color:#d2d2d2; font-size:16px;}.sysFunc{color:#627cf6; ...
- bzoj 3757 苹果树(树上莫队算法)
[题意] 有若干个询问,询问路径u,v上的颜色总数,另外有要求a,b,意为将a颜色看作b颜色. [思路] vfk真是神系列233. Quote: 用S(v, u)代表 v到u的路径上的结点的集合. 用 ...
- javascript中=、==、===区别详解
javascript中=.==.===区别详解今天在项目开发过中发现在一个小问题.在判断n==""结果当n=0时 n==""结果也返回了true.虽然是个小问题 ...