在单元测试的策略中伪对象被广泛使用。他从测试中分离了外部的不需要的因素并且帮助开发人员专注于被测试的功能。
  
  EasyMock是一个在这方面很有名的工具,可以在运行时为给定的接口创建伪对象。伪对象的行为可以在测试用例中的执行测试代码之前被定义。EasyMock基于java.lang.reflect.Proxy,他可以根据给定的接口创建动态代理类或者对象。但因为使用Proxy使得他有一个天生的缺陷:只能创建基于接口的伪对象。
  
  Mocquer是一个类似的工具,但他扩展了EasyMock的功能能够支持创建类的伪对象。
  
  Mocquer介绍
  
  Mocquer基于Dunamis项目,被用来为特定的类或接口生成动态代理类或对象。为方便使用,他遵循EasyMock的类和方法的命名规范,只是在内部使用不同的实现方法。
  
  MockControl是Mocquer项目中重要的类。他被用来控制伪对象的生命周期和行为定义。这个类中有四类方法。
  
  1、生命周期控制方法:
  
  ·public void replay();
  ·public void verify();
  ·public void reset();
  
  伪对象在他的生命周期中有三种状态:准备态、工作态、验证态。

Figure 1. Mock object life cycle
  
  刚开始,伪对象处于准备态,他的表现行为可以在这里定义。replay()将改变伪对象的状态为工作态。在这个状态中所有伪对象的方法调用将会遵循在准备态下定义的行为。在verify()调用后,伪对象处于验证态。MockControl会比较伪对象的预定义行为与实际行为是否匹配。匹配规则依赖于使用的MockControl类型,这个会在稍后解释。开发人员可以在需要时调用replay()来重现预定义的行为。而任何状态下调用reset()将会清除状态历史并重置为初始的准备态。
  
  2、工厂方法
  
  ·public static MockControl createNiceControl(...);
  ·public static MockControl createControl(...);
  ·public static MockControl createStrictControl(...);
  
  Mocquer提供了三种MockControl:宽松的,普通的和严格的。开发人员可以在自己的测试用例中根据测试的内容(测试点)和测试的执行方式(测试策略)选择相应的MockControl。宽松的MockControl是随意的,他不关心伪对象中方法调用的顺序,甚至未预期的方法调用,只是返回一个缺省值(依赖于方法的返回值)。普通的MockControl比宽松的MockControl严格些,未预期的方法调用会导致AssertionFailedError异常。严格的MockControl是严格的,如果伪对象在工作态下方法调用的顺序与准备态的不同,会抛出AssertionFailedError异常。
下面是每一个工厂方法的两个不同版本。
  public static MockControl createXXXControl(Class clazz); public static MockControl createXXXControl(Class clazz,  Class[] argTypes, Object[] args);
  
  如果类是作为接口来模拟的或者他有一个公共或保护的缺省构造函数,则第一个版本的方法会被使用。否则第二个版本会被用来定义标识和提供参数给期望的构造函数。
  
  例如,假设ClassWithNoDefaultConstructor是一个没有缺省构造函数的类:
  
  public class ClassWithNoDefaultConstructor {
  public ClassWithNoDefaultConstructor(int i) {
  ...
  }
  ...
  }
  
  ·伪对象获取方法
  
  public Object getMock();
  
  每一个MockControl包含一个生成的伪对象的引用。开发人员可以使用这个方法取得伪对象并且转换为实际的对象类型。
  
  //get mock control
  MockControl control = MockControl.createControl(Foo.class);
  //Get the mock object from mock control
  Foo foo = (Foo) control.getMock();
  
  ·行为定义方法
  
  public void setReturnValue(... value);
  public void setThrowable(Throwable throwable);
  public void setVoidCallable();
  public void setDefaultReturnValue(... value);
  public void setDefaultThrowable(Throwable throwable);
  public void setDefaultVoidCallable();
  public void setMatcher(ArgumentsMatcher matcher);
  public void setDefaultMatcher(ArgumentsMatcher matcher);