`
369128396
  • 浏览: 85216 次
  • 性别: Icon_minigender_2
  • 来自: 北京
社区版块
存档分类
最新评论

EasyMock使用手记

阅读更多
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 的话,就失去了测试的意义。

分享到:
评论

相关推荐

    EasyMock 使用方法与原理剖析

    EasyMock单元测试的扩展; EasyMock简介(抽象类接口做测试); EasyMock来进行测试; EasyMock如何打桩; EasyMock实践指南;...EasyMock使用技巧;...EasyMock使用简明手册;...EasyMock使用手记; 用Mock object进行隔离测试;

    Easy Mock 详解

    EasyMock单元测试的扩展; EasyMock简介(抽象类接口做测试); EasyMock来进行测试; EasyMock如何打桩; EasyMock实践指南; EasyMock使用技巧;...EasyMock使用简明手册;...EasyMock使用手记; 用Mock object进行隔离测试;

    人大金仓数据库备份脚本

    人大金仓数据库备份脚本

    智能制造:MATLAB_开发AGV调度系统动态路径规划算法.pdf

    文档支持目录章节跳转同时还支持阅读器左侧大纲显示和章节快速定位,文档内容完整、条理清晰。文档内所有文字、图表、函数、目录等元素均显示正常,无任何异常情况,敬请您放心查阅与使用。文档仅供学习参考,请勿用作商业用途。 你是否渴望高效解决复杂的数学计算、数据分析难题?MATLAB 就是你的得力助手!作为一款强大的技术计算软件,MATLAB 集数值分析、矩阵运算、信号处理等多功能于一身,广泛应用于工程、科学研究等众多领域。 其简洁直观的编程环境,让代码编写如同行云流水。丰富的函数库和工具箱,为你节省大量时间和精力。无论是新手入门,还是资深专家,都能借助 MATLAB 挖掘数据背后的价值,创新科技成果。别再犹豫,拥抱 MATLAB,开启你的科技探索之旅!

    开源模型应用落地-Podcastfy-从文本到声音的智能跃迁-Gradio(一)

    DeepSeek 15天指导手册——从入门到精通文件生成的PodCast音频

    蓝桥杯嵌入式按键外设代码供学习例程

    嵌入式按键学习资源。蓝桥杯嵌入式按键外设代码供学习例程。

    Unity游戏多语言功能+预览修改工具

    配合博客内容食用

    建筑材料优化:MATLAB离散元法在混凝土配比仿真中的应用.pdf

    文档支持目录章节跳转同时还支持阅读器左侧大纲显示和章节快速定位,文档内容完整、条理清晰。文档内所有文字、图表、函数、目录等元素均显示正常,无任何异常情况,敬请您放心查阅与使用。文档仅供学习参考,请勿用作商业用途。 你是否渴望高效解决复杂的数学计算、数据分析难题?MATLAB 就是你的得力助手!作为一款强大的技术计算软件,MATLAB 集数值分析、矩阵运算、信号处理等多功能于一身,广泛应用于工程、科学研究等众多领域。 其简洁直观的编程环境,让代码编写如同行云流水。丰富的函数库和工具箱,为你节省大量时间和精力。无论是新手入门,还是资深专家,都能借助 MATLAB 挖掘数据背后的价值,创新科技成果。别再犹豫,拥抱 MATLAB,开启你的科技探索之旅!

    How To Avoid Status Quo Bias- Human Enhancement and ... 如何避免现状偏见:人类增强.doc

    How To Avoid Status Quo Bias- Human Enhancement and ... 如何避免现状偏见:人类增强.doc

    ERP成本核算管理系统.rar

    ERP成本核算管理系统.rar

    将曲线拟合为具有固定端点的分段线性函数Matlab代码.rar

    1.版本:matlab2014/2019a/2024a 2.附赠案例数据可直接运行matlab程序。 3.代码特点:参数化编程、参数可方便更改、代码编程思路清晰、注释明细。 4.适用对象:计算机,电子信息工程、数学等专业的大学生课程设计、期末大作业和毕业设计。

    元宇宙数字孪生体构建:MATLAB-UnrealEngine联合开发指南.pdf

    文档支持目录章节跳转同时还支持阅读器左侧大纲显示和章节快速定位,文档内容完整、条理清晰。文档内所有文字、图表、函数、目录等元素均显示正常,无任何异常情况,敬请您放心查阅与使用。文档仅供学习参考,请勿用作商业用途。 你是否渴望高效解决复杂的数学计算、数据分析难题?MATLAB 就是你的得力助手!作为一款强大的技术计算软件,MATLAB 集数值分析、矩阵运算、信号处理等多功能于一身,广泛应用于工程、科学研究等众多领域。 其简洁直观的编程环境,让代码编写如同行云流水。丰富的函数库和工具箱,为你节省大量时间和精力。无论是新手入门,还是资深专家,都能借助 MATLAB 挖掘数据背后的价值,创新科技成果。别再犹豫,拥抱 MATLAB,开启你的科技探索之旅!

    智能制造:MATLAB_实现CNC加工路径优化与仿真验证.pdf

    文档支持目录章节跳转同时还支持阅读器左侧大纲显示和章节快速定位,文档内容完整、条理清晰。文档内所有文字、图表、函数、目录等元素均显示正常,无任何异常情况,敬请您放心查阅与使用。文档仅供学习参考,请勿用作商业用途。 你是否渴望高效解决复杂的数学计算、数据分析难题?MATLAB 就是你的得力助手!作为一款强大的技术计算软件,MATLAB 集数值分析、矩阵运算、信号处理等多功能于一身,广泛应用于工程、科学研究等众多领域。 其简洁直观的编程环境,让代码编写如同行云流水。丰富的函数库和工具箱,为你节省大量时间和精力。无论是新手入门,还是资深专家,都能借助 MATLAB 挖掘数据背后的价值,创新科技成果。别再犹豫,拥抱 MATLAB,开启你的科技探索之旅!

    MATLAB工具箱用于模拟珊瑚礁上所有海洋加热源的热量预算,.rar

    1.版本:matlab2014/2019a/2024a 2.附赠案例数据可直接运行matlab程序。 3.代码特点:参数化编程、参数可方便更改、代码编程思路清晰、注释明细。 4.适用对象:计算机,电子信息工程、数学等专业的大学生课程设计、期末大作业和毕业设计。

    操作系统实验5.docx

    操作系统实验5.docx

    Windows下Python安装与配置教程.markdown

    python安装 本教程将指导您在Windows操作系统上安装和配置Python编程环境,适用于Python 3.x版本(推荐使用最新稳定版,如Python 3.11或3.12)。本教程提供清晰的步骤说明,确保初学者也能顺利完成安装和基本配置。

    爱国者手写板压缩包11

    爱国者手写板

    电子计算机见习总结.docx

    电子计算机见习总结.docx

    数字孪生+强化学习:MATLAB实现智能制造产线动态调度系统.pdf

    文档支持目录章节跳转同时还支持阅读器左侧大纲显示和章节快速定位,文档内容完整、条理清晰。文档内所有文字、图表、函数、目录等元素均显示正常,无任何异常情况,敬请您放心查阅与使用。文档仅供学习参考,请勿用作商业用途。 你是否渴望高效解决复杂的数学计算、数据分析难题?MATLAB 就是你的得力助手!作为一款强大的技术计算软件,MATLAB 集数值分析、矩阵运算、信号处理等多功能于一身,广泛应用于工程、科学研究等众多领域。 其简洁直观的编程环境,让代码编写如同行云流水。丰富的函数库和工具箱,为你节省大量时间和精力。无论是新手入门,还是资深专家,都能借助 MATLAB 挖掘数据背后的价值,创新科技成果。别再犹豫,拥抱 MATLAB,开启你的科技探索之旅!

Global site tag (gtag.js) - Google Analytics