`
369128396
  • 浏览: 85485 次
  • 性别: 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进行隔离测试;

    thymeleaf-2.0.15.jar中文文档.zip

    # 压缩文件中包含: 中文文档 jar包下载地址 Maven依赖 Gradle依赖 源代码下载地址 # 本文件关键字: jar中文文档.zip,java,jar包,Maven,第三方jar包,组件,开源组件,第三方组件,Gradle,中文API文档,手册,开发手册,使用手册,参考手册 # 使用方法: 解压最外层zip,再解压其中的zip包,双击 【index.html】 文件,即可用浏览器打开、进行查看。 # 特殊说明: ·本文档为人性化翻译,精心制作,请放心使用。 ·只翻译了该翻译的内容,如:注释、说明、描述、用法讲解 等; ·不该翻译的内容保持原样,如:类名、方法名、包名、类型、关键字、代码 等。 # 温馨提示: (1)为了防止解压后路径太长导致浏览器无法打开,推荐在解压时选择“解压到当前文件夹”(放心,自带文件夹,文件不会散落一地); (2)有时,一套Java组件会有多个jar,所以在下载前,请仔细阅读本篇描述,以确保这就是你需要的文件;

    javassist-3.25.0-GA.jar中文-英文对照文档.zip

    # 压缩文件中包含: 中文-英文对照文档 jar包下载地址 Maven依赖 Gradle依赖 源代码下载地址 # 本文件关键字: jar中文-英文对照文档.zip,java,jar包,Maven,第三方jar包,组件,开源组件,第三方组件,Gradle,中文API文档,手册,开发手册,使用手册,参考手册 # 使用方法: 解压最外层zip,再解压其中的zip包,双击 【index.html】 文件,即可用浏览器打开、进行查看。 # 特殊说明: ·本文档为人性化翻译,精心制作,请放心使用。 ·只翻译了该翻译的内容,如:注释、说明、描述、用法讲解 等; ·不该翻译的内容保持原样,如:类名、方法名、包名、类型、关键字、代码 等。 # 温馨提示: (1)为了防止解压后路径太长导致浏览器无法打开,推荐在解压时选择“解压到当前文件夹”(放心,自带文件夹,文件不会散落一地); (2)有时,一套Java组件会有多个jar,所以在下载前,请仔细阅读本篇描述,以确保这就是你需要的文件;

    “计及源荷双重不确定性的虚拟电厂微网日前随机优化调度模型设计与实现(基于蒙特卡洛与概率距离法处理不确定性变量)”

    内容概要:本文详细介绍了利用MATLAB进行虚拟电厂日前随机优化调度的方法。首先,通过蒙特卡洛模拟生成大量光伏出力和负荷的随机场景,考虑到光伏出力和负荷预测的不确定性。接着,采用概率距离削减法将大量场景缩减为少数典型场景,确保计算效率的同时保留重要特征。然后,构建随机优化模型,将燃气轮机、储能、弃光等成本纳入目标函数,并设置严格的功率平衡和设备出力限制作为约束条件。最终,使用CPLEX求解器求解该混合整数规划问题,得到最优调度方案。实验结果显示,相比传统确定性优化,随机优化显著提高了系统的鲁棒性和经济效益。 适合人群:从事电力系统研究、虚拟电厂调度、智能电网优化的研究人员和技术人员。 使用场景及目标:适用于需要处理光伏出力和负荷预测不确定性的虚拟电厂调度场景,旨在提高调度方案的稳定性和经济性,降低运营风险。 其他说明:文中提供了详细的MATLAB代码片段,帮助读者理解和实现具体的算法步骤。此外,还给出了若干实用技巧和注意事项,如场景削减时的概率归一化、储能SOC约束的跨场景耦合等。

    aws-java-sdk-s3-1.12.249.jar中文文档.zip

    # 压缩文件中包含: 中文文档 jar包下载地址 Maven依赖 Gradle依赖 源代码下载地址 # 本文件关键字: jar中文文档.zip,java,jar包,Maven,第三方jar包,组件,开源组件,第三方组件,Gradle,中文API文档,手册,开发手册,使用手册,参考手册 # 使用方法: 解压最外层zip,再解压其中的zip包,双击 【index.html】 文件,即可用浏览器打开、进行查看。 # 特殊说明: ·本文档为人性化翻译,精心制作,请放心使用。 ·只翻译了该翻译的内容,如:注释、说明、描述、用法讲解 等; ·不该翻译的内容保持原样,如:类名、方法名、包名、类型、关键字、代码 等。 # 温馨提示: (1)为了防止解压后路径太长导致浏览器无法打开,推荐在解压时选择“解压到当前文件夹”(放心,自带文件夹,文件不会散落一地); (2)有时,一套Java组件会有多个jar,所以在下载前,请仔细阅读本篇描述,以确保这就是你需要的文件;

    农产品销售管理系统 - Java课程设计项目 - SpringBoot毕业设计 - Vue+MySQL期末大作业

    农产品销售管理系统基于SpringBoot+MyBatisPlus+Vue+MySQL开发,专为Java课程设计、毕业设计及初学者打造。适合作为Java期末大作业或实战练手项目。采用IDEA开发,技术主流,代码规范,帮助快速掌握全栈开发技能,助力Java学习与答辩!

    aws-java-sdk-s3-1.12.254.jar中文-英文对照文档.zip

    # 压缩文件中包含: 中文-英文对照文档 jar包下载地址 Maven依赖 Gradle依赖 源代码下载地址 # 本文件关键字: jar中文-英文对照文档.zip,java,jar包,Maven,第三方jar包,组件,开源组件,第三方组件,Gradle,中文API文档,手册,开发手册,使用手册,参考手册 # 使用方法: 解压最外层zip,再解压其中的zip包,双击 【index.html】 文件,即可用浏览器打开、进行查看。 # 特殊说明: ·本文档为人性化翻译,精心制作,请放心使用。 ·只翻译了该翻译的内容,如:注释、说明、描述、用法讲解 等; ·不该翻译的内容保持原样,如:类名、方法名、包名、类型、关键字、代码 等。 # 温馨提示: (1)为了防止解压后路径太长导致浏览器无法打开,推荐在解压时选择“解压到当前文件夹”(放心,自带文件夹,文件不会散落一地); (2)有时,一套Java组件会有多个jar,所以在下载前,请仔细阅读本篇描述,以确保这就是你需要的文件;

    物联网设备开发_蓝牙低能耗BLE技术_小米手环1非心率版数据读取与控制_实现Android平台下小米手环1代非心率版设备的蓝牙连接_步数数据获取_电量监测_震动控制功能_适用于An.zip

    物联网设备开发_蓝牙低能耗BLE技术_小米手环1非心率版数据读取与控制_实现Android平台下小米手环1代非心率版设备的蓝牙连接_步数数据获取_电量监测_震动控制功能_适用于An

    安卓系统开发_蓝牙低功耗监测与音频控制_支持AirPods全系列电量显示与入耳检测_为OPPO手机深度优化并兼容其他安卓设备的智能耳机管理助手_实现耳机离耳自动暂停和入耳自动播放功.zip

    安卓系统开发_蓝牙低功耗监测与音频控制_支持AirPods全系列电量显示与入耳检测_为OPPO手机深度优化并兼容其他安卓设备的智能耳机管理助手_实现耳机离耳自动暂停和入耳自动播放功

    基于.NET 6的WPF工具:集成OpenCVSharp与ReactiveUI,深度学习目标识别及3D点云数据处理

    内容概要:本文介绍了一个基于.NET 6 WPF框架构建的多功能图像处理与3D点云显示工具。该项目集成了ReactiveUI用于响应式UI设计,OpenCVSharp用于图像处理,以及HelixToolkit用于3D点云渲染。通过ReactiveUI实现了参数的实时调整和图像处理的即时反馈,如Canny边缘检测、高斯模糊等。此外,项目还包括了YOLOv4的目标检测功能,支持多种3D点云格式的导入和渲染。文中详细描述了各个模块的技术实现细节,包括性能优化和常见问题的解决方案。 适合人群:熟悉.NET和WPF框架的开发者,尤其是对图像处理和3D点云感兴趣的研发人员。 使用场景及目标:① 实时调整图像处理参数,快速验证算法效果;② 作为3D点云查看器,支持多种格式的点云数据;③ 集成YOLOv4进行目标检测,适用于计算机视觉领域的研究和开发。 其他说明:项目仍在持续改进中,源码中有许多待优化的地方,提供了丰富的扩展空间和技术挑战。

    人工势场法路径规划Matlab代码详解:涵盖两种方法的编写与注释,公式解释及A*、rrt等算法整合

    内容概要:本文探讨了机器人路径规划领域的多种经典算法,重点介绍了人工势场法的基本原理和Matlab实现方法。文中不仅提供了传统人工势场法的具体代码实现,还针对其易陷入局部最优的问题提出了改进措施,如引入随机扰动。此外,简要提及了A*和RRT算法的特点及其实现思路。通过详细的代码解析和参数调优指南,帮助读者更好地理解和应用这些算法。 适合人群:对机器人路径规划感兴趣的初学者以及有一定编程基础的研究人员。 使用场景及目标:适用于希望深入了解人工势场法的工作原理并掌握其具体实现的技术人员。目标是能够独立编写和优化路径规划算法,特别是在Matlab环境下进行实验和验证。 其他说明:文章附带了完整的代码片段和注释,便于读者实践操作。同时强调了不同算法的选择依据和应用场景,鼓励读者根据实际情况灵活选用合适的方法。

    威纶通触摸屏一机多屏程序

    内容概要:本文深入介绍了威纶通触摸屏一机多屏程序及其与FX3U系列PLC和MODBUS通讯的集成应用。首先,文章阐述了系统的硬件架构,即一个FX3U系列PLC搭配四个MT6051ip触摸屏的工作原理。接着,详细解析了威纶通模板的特点,特别是梯形图的详尽注释,便于理解和维护。此外,文章还探讨了PLC与上位机的MODBUS通讯设置,包括波特率、数据位、停止位等参数的具体配置方法。最后,强调了该系统的学习意义和借鉴价值,适用于新手和资深工程师。 适合人群:从事自动化控制领域的工程师和技术人员,尤其是那些希望深入了解PLC、触摸屏和MODBUS通讯的人群。 使用场景及目标:①帮助工程师快速掌握威纶通触摸屏的一机多屏配置;②提高PLC与触摸屏、上位机之间的通讯效率;③优化中小型企业生产线的监控系统,提升生产效率和稳定性。 其他说明:文中提供的实例和代码片段有助于读者更好地理解和实践相关技术,同时附带了一些实用的小技巧,如心跳检测和双看门狗设计,增强了系统的可靠性和容错能力。

    CNC雕刻机STM32F407源码详解:带详细中文注解与原理图解析

    内容概要:本文深入剖析了一款基于STM32F407的CNC雕刻机控制系统,涵盖硬件原理图和源码实现。首先介绍了步进电机驱动部分,详细解释了XYZ三轴的方向引脚配置及时序控制,确保电机平稳运行。接着讨论了PWM脉冲生成的核心配置,通过定时器精确控制雕刻精度,并解决了高速雕刻时的脉冲丢失问题。串口通信部分采用DMA+空闲中断,显著提升了数据处理效率。运动插补算法利用定时器触发DMA传输脉冲,实现高效的三轴联动。此外,文中还涉及了G代码解析、运动前瞻算法以及硬件设计中的防呆措施,如IO口的TVS二极管和RC滤波。最后,分享了一些调试经验和隐藏的开发彩蛋,如通过LED灯效显示工作状态和电流检测实现堵转保护。 适合人群:具备嵌入式开发基础,尤其是对STM32和CNC雕刻机感兴趣的开发者和技术爱好者。 使用场景及目标:①帮助开发者理解和实现CNC雕刻机的控制系统;②提供详细的硬件和软件设计方案,便于动手制作;③分享调试技巧和实战经验,提高系统的稳定性和可靠性。 阅读建议:本文不仅提供了详细的代码实现和硬件设计,还包括了许多实战经验和调试技巧,因此在阅读过程中应重点关注这些细节,并尝试复现相关功能。

    aws-java-sdk-s3-1.12.242.jar中文-英文对照文档.zip

    # 压缩文件中包含: 中文-英文对照文档 jar包下载地址 Maven依赖 Gradle依赖 源代码下载地址 # 本文件关键字: jar中文-英文对照文档.zip,java,jar包,Maven,第三方jar包,组件,开源组件,第三方组件,Gradle,中文API文档,手册,开发手册,使用手册,参考手册 # 使用方法: 解压最外层zip,再解压其中的zip包,双击 【index.html】 文件,即可用浏览器打开、进行查看。 # 特殊说明: ·本文档为人性化翻译,精心制作,请放心使用。 ·只翻译了该翻译的内容,如:注释、说明、描述、用法讲解 等; ·不该翻译的内容保持原样,如:类名、方法名、包名、类型、关键字、代码 等。 # 温馨提示: (1)为了防止解压后路径太长导致浏览器无法打开,推荐在解压时选择“解压到当前文件夹”(放心,自带文件夹,文件不会散落一地); (2)有时,一套Java组件会有多个jar,所以在下载前,请仔细阅读本篇描述,以确保这就是你需要的文件;

    karson711_JKCircleViewDemo_12888_1745868188120.zip

    karson711_JKCircleViewDemo_12888_1745868188120

    医学超声成像_基于FPGA和CYUSB30的超声信号处理_超声波发射与AD采集_剪切波弹性成像_多通道数据同步传输_高速BULK传输_URAT状态控制_4096点扫描线采集_30.zip

    医学超声成像_基于FPGA和CYUSB30的超声信号处理_超声波发射与AD采集_剪切波弹性成像_多通道数据同步传输_高速BULK传输_URAT状态控制_4096点扫描线采集_30

    一些小游戏,比较好玩,windows10系统运行

    一些小游戏,比较好玩,windows10系统运行

    三菱FX3U PLC画圆程序:同心的圆及子程序循环插补法

    内容概要:本文详细介绍了如何利用三菱FX3U PLC通过360等份插补的方法绘制三个同心圆。首先将圆分解为360个等分点,通过三角函数实时计算各点的X/Y坐标,采用子程序循环调用来实现连续运动。文中提供了具体的代码片段,展示了如何通过寄存器配置和三角函数计算来精确控制圆的绘制过程。此外,还讨论了如何通过调整参数实现不同的图形效果,如虚线圆、螺旋线等。并强调了该方法在工业应用中的灵活性和高效性。 适合人群:对PLC编程有一定基础,希望深入了解PLC在工业控制中具体应用的研发人员和技术爱好者。 使用场景及目标:适用于需要进行精密轨迹控制的应用场合,如数控机床、自动化生产线等。主要目标是掌握PLC在复杂轨迹控制中的应用技巧,提高工业控制系统的精度和效率。 其他说明:文中提到的技术不仅限于画圆,还可以扩展应用于其他复杂的几何图形绘制,如多边形、螺旋线等。并且可以通过进一步优化参数设置,提升系统的响应速度和稳定性。

    chromedriver-mac-arm64-138.0.7153.0.zip

    chromedriver-mac-arm64-138.0.7153.0.zip

Global site tag (gtag.js) - Google Analytics