`
yanghongxia9
  • 浏览: 115122 次
  • 性别: Icon_minigender_1
  • 来自: 深圳
社区版块
存档分类
最新评论

jmock

    博客分类:
  • java
 
阅读更多
一、介绍
    JMock是一个使用模拟对象机制测试Java代码的开发包。模拟对象(Mock Object)可以取代真实对象的位置,用于测试一些与真实对象进行交互或依赖于真实对象的功能,模拟对象的背后目的就是创建一个轻量级的、可控制的对象来代替测试中需要的真实对象,模拟真实对象的行为和功能,方便我们的测试。JMock就是这种机制的实现,使用JMock我们可以快速创建模拟对象,定义交互过程中的约束条件等,同时JMock也是易扩展的,你可以很方便添加自定义的需求。

mock对象:这个虚拟的对象就是mock对象。mock对象就是真实对象在调试期间的代替品。

mock对象使用范畴:

  真实对象具有不可确定的行为,产生不可预测的效果,(如:股票行情,天气预报)

  真实对象很难被创建的

  真实对象的某些行为很难被触发

  真实对象实际上还不存在的(和其他开发小组或者和新的硬件打交道) 等等...

  使用mock对象测试的关键步骤:

  使用一个接口来描述这个对象

  在产品代码中实现这个接口

  在测试代码中实现这个接口

  在被测试代码中只是通过接口来引用对象,所以它不知道这个引用的对象是真实对象还是mock对象。

MockObject概述

  使用Mock Object进行测试,主要是用来模拟那些在应用中不容易构造(如HttpServletRequest必须在Servlet容器中才能构造出来)或者比较复杂的对象(如JDBC中的ResultSet对象)从而使测试顺利进行的工具。

  目前,在Java阵营中主要的Mock测试工具有JMock,MockCreator,Mockrunner,EasyMock,MockMaker等,在微软的.Net阵营中主要是Nmock,.NetMock等。

  以下就对在Java中使用的Mock Object进行测试的常用工具做一下使用说明。

  JMock

简介

  准备

  1.获取J2SDK;

  2.获取JUnit V3.8.1(从http://www.junit.org获取开发包);

  3.获取JMock V1.0(从http://www.jmock.org获取JMock开发包)。【这个是jmock1的版本例子】

  4.为了开发方便,建议使用一个好IDE。以下例子中的代码均是在Eclipse V3.0环境下进行的调试。

例子一

  以下是jmock1的版本例子一个简单例子,代码如下:



Java代码 
1.package test1;  
2. 
3.  import org.jmock.*;  
4.  import javax.servlet.http.*;  
5. 
6.  public class MockRequestTest extends MockObjectTestCase{  
7. 
8.  public void testMockRequest1(){  
9. 
10.  //构造一个Mock对象  
11.  Mock mock = new Mock(HttpServletRequest.class);  
12. 
13.  //设置要执行的操作,以下设置表示要调用一次HttpServletRequest对象的  
14.  //getParameter方法,传递的参数是"name",期望的返回是"kongxx"  
15. 
16.  mock.eXPects(once()).method("getParameter").with(eq("name")).will(returnValue("kongxx"));  
17. 
18.  //根据Mock对象获取一个HttpServletRequest对象  
19.  HttpServletRequest request = (HttpServletRequest)mock.proxy();  
20. 
21.  //断言调用结果  
22.  assertEquals("kongxx" ,request.getParameter("name"));  
23. 
24.  }  
25. 
26.  public void testMockRequest2(){  
27. 
28.  //构造一个Mock对象  
29.  Mock mock = new Mock(HttpServletRequest.class);  
30. 
31.  //设置要执行的操作,以下设置表示要调用一次HttpServletRequest对象的  
32.  //getParameter方法,传递的参数是"name",期望的返回是"kongxx"  
33. 
34.  mock.expects(once()).method("getParameter").with(eq("name")).will(returnValue("kongxx"));  
35. 
36.  //根据Mock对象获取一个HttpServletRequest对象  
37.  HttpServletRequest request = (HttpServletRequest)mock.proxy();  
38. 
39.  //调用HttpServletRequest对象的方法  
40.  request.getParameter("name");  
41. 
42.  //验证执行结果  
43.  mock.verify();  
44.  }  
45.  } 
package test1;

  import org.jmock.*;
  import javax.servlet.http.*;

  public class MockRequestTest extends MockObjectTestCase{

  public void testMockRequest1(){

  //构造一个Mock对象
  Mock mock = new Mock(HttpServletRequest.class);

  //设置要执行的操作,以下设置表示要调用一次HttpServletRequest对象的
  //getParameter方法,传递的参数是"name",期望的返回是"kongxx"

  mock.eXPects(once()).method("getParameter").with(eq("name")).will(returnValue("kongxx"));

  //根据Mock对象获取一个HttpServletRequest对象
  HttpServletRequest request = (HttpServletRequest)mock.proxy();

  //断言调用结果
  assertEquals("kongxx" ,request.getParameter("name"));

  }

  public void testMockRequest2(){

  //构造一个Mock对象
  Mock mock = new Mock(HttpServletRequest.class);

  //设置要执行的操作,以下设置表示要调用一次HttpServletRequest对象的
  //getParameter方法,传递的参数是"name",期望的返回是"kongxx"

  mock.expects(once()).method("getParameter").with(eq("name")).will(returnValue("kongxx"));

  //根据Mock对象获取一个HttpServletRequest对象
  HttpServletRequest request = (HttpServletRequest)mock.proxy();

  //调用HttpServletRequest对象的方法
  request.getParameter("name");

  //验证执行结果
  mock.verify();
  }
  } 编译并将其当做一个Test Case运行,会发现两个测试方法均测试成功。



实例2 jmock2:getting started with junit4  

(http://www.blogjava.net/alex0927/archive/2008/06/20/209474.html)



1.测试接口:
IHelloService:

1 public interface IHelloService {
 

   String sayHelloToSomebody(String name);

}
IMPL:

1 public class HelloServiceImpl implements IHelloService {
2

9     public String sayHelloToSomebody(String name) {
10         return "HELLO," + name + "!";
11     }
12
13 }
Test Case:

1 public class IHelloServiceTest extends TestCase {
2     private Mockery context = new JUnit4Mockery();
3     private IHelloService helloService;
4
5     /**
6      * @throws java.lang.Exception
7      */
8     @Before
9     public void setUp() throws Exception {
10         // set up
11         helloService = context.mock(IHelloService.class);
12     }
13
14     /**
15      * Test method for
16      * {@link org.hook.jmock.firstcase.HelloServiceImpl#sayHelloToSomebody(java.lang.String)}.
17      */
18     @Test
19     public void testSayHelloToSomebody() {
20         final String message = "HELLO,alex!";
21         final String name = "alex";
22         // expectations
23         context.checking(new Expectations() {
24             {
25                 one(helloService).sayHelloToSomebody(name);
26                 will(returnValue(message));
27             }
28         });
29         // execute
30         String result = helloService.sayHelloToSomebody(name);
31         // verify
32         context.assertIsSatisfied();
33         assertSame(result, message);
34     }
35 } OK,跑下测试,green bar...
2.测试类:
HelloService:

1 public class HelloService {

7     public String sayHelloToSomebody(String name) {
8         return "HELLO," + name + "!";
9     }
10 } Test Case:

1 public class HelloServiceTest extends TestCase {
2     private Mockery context;
3     private HelloService helloService;
4
5     /**
6      * @throws java.lang.Exception
7      */
8     @Before
9     public void setUp() throws Exception {
10         context = new JUnit4Mockery();
11         // 声明针对类进行mock,针对接口则会采用动态代理,不需要声明
12         context.setImposteriser(ClassImposteriser.INSTANCE);
13         helloService = context.mock(HelloService.class);
14     }
15
16     /**
17      * Test method for
18      * {@link org.hook.jmock.firstcase.HelloService#sayHelloToSomebody(java.lang.String)}.
19      */
20     @Test
21     public void testSayHelloToSomebody() {
22         final String message = "HELLO,vivian!";
23         final String name = "vivian";
24         // expectations
25         context.checking(new Expectations() {
26             {
27                 one(helloService).sayHelloToSomebody(name);
28                 will(returnValue(message));
29             }
30         });
31         // execute
32         String result = helloService.sayHelloToSomebody(name);
33         // verify
34         context.assertIsSatisfied();
35         assertSame(result, message);
36     }
37 } OK,跑下测试,green bar again...





二、【应用文档】:
1. 如何校验expectations中的规则?
使用JMock时,一般会通过如下代码指定expectations。

private Mockery   context = new Mockery();
context.checking(new Expectations() {
{     
      ... expectations go here ... 
        }
}); 为了校验expectations中的规则是否都满足,可以在测试完成后通过增加 context.assertIsSatisfied()方法来验证expectations是否满足。

    //test assertions and test logic code. 
      context.assertIsSatisfied(); 若校验不成果,测试将失败。



2. one和oneOf的区别?

one(mockObject) 以后会depreacted; 即one方法即将过时。所以因该使用oneOf(mockObject) 来代替.鉴于我们目前使用的是JMock2.4版,所以大家还是直接使用one就ok了。oneOf是2.51版中的内容。

3. 如何设定使用expectation的语法来指定同一个方法连续调用时返回不同的值?
有两种方法,第一种就是直接通过多次调用 will(returnValue(X))来指定。如

oneOf (anObject).doSomething(); will(returnValue(10));
oneOf (anObject).doSomething(); will(returnValue(20));
oneOf (anObject).doSomething(); will(returnValue(30)); 第一次调用时会返回10,第二次会返回20,第三次会返回30.

然而第一一种方法会增加维护成本,且缺乏可控性。JMock提供了第二种方法,即通过onConsecutiveCalls的action来实现返回不同的返回值。如:

atLeast(1).of (anObject).doSomething(); 
will(onConsecutiveCalls( returnValue(10),  returnValue(20),  returnValue(30))); 这里atLeast (1)表明doSomething方法将至少被调用一次,但不超过3次。且调用的返回值分别是10、20、30.

4. 如何指定mock的方法抛出异常?
在will方法中直接使用throwException的action。参考如下语法:

oneOf (anObject).doSomething();    will(throwException(new UserDefinedException()); 5. 如何指定被mock方法的调用次数?
参考Jmock的文档,调用次数可以通过 oneOf,exactly(times).of, atLeast(times).of, atMost(times).of, between(min, max).of, allowing, ignoring, never 等来指定。具体含义见下表。

JMock defines the following cardinalities:
one  The invocation is expected once and once only. 
exactly(times).of  The invocation is expected exactly n times. Note: one is a convenient shorthand for exactly(1). 
atLeast(times).of  The invocation is expected at least n times. 
atMost(times).of  The invocation is expected at most n times. 
between(min, max).of  The invocation is expected at least min times and at most max times. 
allowing  The invocation is allowed any number of times but does not have to happen. 
ignoring  The same as allowing. Allowing or ignoring should be chosen to make the test code clearly express intent. 
never  The invocation is not expected at all. This is used to make tests more explicit and so easier to understand. 

需要强调的是allowing和ignoring的规则不会破坏 context.assertIsSatisfied()的校验。

6. 什么时候使用expect,还有allowing呢?
根据JMock的cookbook。如果方法的调用是allowing的,哪么在测试时,这个方法允许被调用,并且如果方法未被调用测试仍然会通 过。反之,如果一个方法是expected的(即通过one,oneOf,exactly(times).of, atLeast(times).of, atMost(times).of, between(min, max).of 等指定次数的),则该方法必须满足次数的要求,否则测试将失败。附上Cookbook上的内容参考。



Expecting vs. Allowing

The most important distinction that cardinalities express is between expecting and allowing an invocation.

If an invocation is allowed, it can occur during a test run, but the test still passes if the invocation does not occur. If an invocation is expected, on the other hand, it must occur during a test run; if it does not occur, the test fails. When defining expectations you must choose whether to expect or allow each invocation. In general, we find that tests are kept flexible if you allow queries and expect commands. A query is a method with no side effects that does nothing but query the state of an object and a command is a method with side effects that may, or may not, return a result. Of course, this does not hold all the time but it’s a useful rule of thumb to follow if there are no other constraints on the number of times you expect a method to be called in your test.

7. 如何指定方法被调用的次序(Sequence)呢?
当需要指定方法调用次序时,可以首先声明一个JMock 的sequence对象。

final Sequence sequenceName= context.sequence("sequenceName"); 然后通过增加inSequence(sequenceName)的语法来指定不同方法的调用次序:

oneOf (turtle).forward(10); inSequence(sequenceName);
oneOf (turtle).turn(45); inSequence(sequenceName);
atMost(5).of (turtle).forward(10); inSequence(sequenceName);
oneOf (turtle).backward(20); inSequence(sequenceName); 这样方法被调用的顺序必须按照forwar、turn、forward、backward的顺序来进行。此外如果Sequence中的方法的expectations是allowing的,则将被Sequence忽略。

8 如何使用JMock的状态机state。
状态机state和Sequence的使用方法类似。首先声明state。

//构建状态机,并确定初始状态为"initialState"。 final States stateMachineName = context.states("stateMachineName ").startsAs("initialState");

然后通过如下语法来使用

The following clauses constrain invocations to occur within specific states and define how an invocation will change the current state of a state machine.

when(state-machine.is(”state-name”));  Constrains the last expectation to occur only when the state machine is in the named state. 
when(state-machine.isNot(”state-name”));  Constrains the last expectation to occur only when the state machine is not in the named state. 
then(state-machine.is(”state-name”));  Changes the state of state-machine to the named state when the invocation occurs. 

实例:

//声明状态机" pen",初始状态为"up".
  final States pen = context.states("pen").startsAs("up");
//penDown执行后,状态机迁移为"down".
  oneOf (turtle).penDown(); then(pen.is("down"));
//forward执行的条件是状态机处于"down"状态;
  oneOf (turtle).forward(10); when(pen.is("down"));
//turn执行的条件是状态机处于"down"状态.
  oneOf (turtle).turn(90); when(pen.is("down"));
//forward执行的条件是状态机处于"down"状态;
  oneOf (turtle).forward(10); when(pen.is("down"));
//penUp执行后,状态机迁移到"up"状态.
  oneOf (turtle).penUp(); then(pen.is("up");
分享到:
评论
1 楼 Sailer164 2011-10-10  
不错,谢谢

相关推荐

    Jmock2.6 jar包

    **Jmock2.6 Jar包**是Java编程领域中用于单元测试的重要库,它提供了模拟对象的功能,使得开发者能够在测试代码时对复杂依赖关系进行控制和隔离。在本文中,我们将深入探讨Jmock2.6的核心特性、使用场景以及如何在...

    JMock

    **JMock 深度解析** JMock 是一个流行的开源测试框架,专为Java开发者设计,用于模拟对象的行为,特别是在单元测试中。它允许程序员在不依赖真实对象的情况下测试代码,提高了测试的效率和隔离性。这篇详尽的讨论将...

    jmock2.5.1.zip

    《jMock 2.5.1:模拟与测试的艺术》 在软件开发中,单元测试是确保代码质量的重要环节,而模拟(Mocking)技术则是单元测试中的关键工具。jMock,作为Java平台上的一个开源模拟框架,为开发者提供了一种高效、灵活...

    jmock-2.5.1-javadoc

    《jMock 2.5.1:模拟对象与单元测试的艺术》 jMock是一个强大的Java模拟框架,它在软件开发的单元测试阶段扮演着至关重要的角色。jMock 2.5.1是该框架的一个版本,它提供了丰富的功能,帮助开发者创建虚拟对象,...

    jmock-2.6.0-jars

    【jmock-2.6.0-jars】这个压缩包主要包含了`jmock`库的2.6.0版本的jar文件以及相关的源代码。`jmock`是Java平台上的一个模拟框架,它允许开发者在单元测试中创建和控制对象的行为,以便能够隔离测试并精确地指定期望...

    JMOCK 帮助 网页 文档

    **JMock 概述** JMock 是一个Java平台上的单元测试框架,专门用于模拟对象,以便在测试过程中控制和验证对象的行为。它基于EasyMock库,但提供了更强大的功能,尤其是对于处理复杂交互和顺序的场景。JMock使得...

    jmock-1.2.0-jars.zip

    《JMock:模拟对象软件测试工具的深度解析》 在软件开发过程中,单元测试是确保代码质量的关键步骤。为了有效地进行单元测试,我们常常需要模拟(mock)对象,以便隔离测试目标并控制其行为。这就是JMock的作用所在...

    jmock-1.2.0-jars.rar

    《JMock 1.2.0 - 模拟与测试的艺术》 JMock 是一个流行的 Java 开源库,专门用于创建和管理模拟对象,以便在单元测试中隔离被测代码。这个压缩包“jmock-1.2.0-jars.rar”包含的是 JMock 1.2.0 版本的 jar 文件,它...

    jmock cookbook 资源整合

    《JMock Cookbook资源整合》是关于Java测试领域中JMock库使用的详细指南,旨在帮助开发者更好地理解和运用这个强大的模拟框架。JMock是一个用于Java应用程序单元测试的工具,它允许程序员模拟对象的行为,以便在孤立...

    jmock-1.2.0.jar

    Maven-Central / jmock / jmock-cglib 1.2.0 Maven-Central / org.apache.activemq / activemq-ra 5.2.05.1.0 Maven-Central / org.apache.maven.shared / maven-dependency-tree 1.21.1 Maven-Central / org.apache...

    jmock2.5.1和easymock3.0

    而JMock和EasyMock则是两种广泛使用的Java单元测试框架,它们允许开发者模拟对象的行为和交互,以便于测试复杂的系统。本资源包含JMock 2.5.1和EasyMock 3.0的库文件,使得开发者在进行单元测试时无需再四处寻找相关...

    jmock jar包及doc文档

    本文将深入探讨JMock库,它是一个强大的Java模拟框架,常用于单元测试,以及如何结合Spring测试模块进行高效测试。 JMock是一个用于创建和验证对象行为的模拟框架,它允许开发者在测试中模拟对象的行为,而不是依赖...

    Jmock Mock 没有接口的类

    JMock 是一个流行的 Java 模拟框架,它使开发者能够创建模拟对象并定义它们的行为和期望。然而,传统上,JMock 主要用于模拟实现了接口的类,那么当我们需要模拟没有接口的类时,该怎么办呢?这就是 JMock 联合 ...

    JMOCK 2.6.0-RC2

    jMock 2: Java 5 and above. Stable: 2.5.1 Binary JARs (includes the source to let IDEs provide context-sensitive help) Javadocs Unstable: 2.6.0-RC2 Binary JARs (includes the source to let IDEs ...

    软件测试资料集合,jtest,jmock

    `jmock-2.6.0-RC2-javadoc.zip`和`jmock-2.5.1-javadoc.zip`包含的是`jmock`的API文档,可以帮助开发者理解和使用其API。`jmock-2.6.0-RC2-jars.zip`和`jmock-2.5.1-jars.zip`则包含了相应的库文件,可以直接在项目...

    使用 FactoryBean结合Jmock实现动态Mock类的注入

    本篇文章将探讨如何结合`FactoryBean`与Jmock库来实现动态Mock类的注入,以便于进行单元测试。 首先,我们需要了解`FactoryBean`的基本用法。`FactoryBean`的`getObject()`方法负责返回一个由工厂生产的对象,而...

    JMOCK使用文档

    **JMock使用文档** 在Java开发中,单元测试是一项至关重要的任务,它能确保代码的质量和可维护性。JMock是一款强大的模拟框架,专门用于Java应用程序的单元测试,特别是对于那些依赖于复杂外部接口或者服务的类。本...

Global site tag (gtag.js) - Google Analytics