有没有办法使用 EasyMock 部分模拟对象?

Posted

技术标签:

【中文标题】有没有办法使用 EasyMock 部分模拟对象?【英文标题】:Is there a way to partially mock an object using EasyMock? 【发布时间】:2012-06-05 05:15:56 【问题描述】:

例如假设我有这个课程:

public class Foo Implements Fooable 
  public void a() 
    // does some stuff
    bar = b();
    // moar coadz
  
  public Bar b() 
    // blah
  
  // ...

我想测试Foo.a。我想模拟Foo.b,因为我正在单独测试该方法。我想象的是这样的:

public class FooTest extends TestCase 
  public void testA() 
    Fooable foo = createPartialMock(
      Fooable.class,  // like with createMock
      Foo  // class where non-mocked method implementations live
    );

    // Foo's implementation of b is not used.
    // Rather, it is replaced with a dummy implementation
    // that records calls that are supposed to be made;
    // and returns a hard coded value (i.e. new Bar()).
    expect(foo.b()).andReturn(new Bar());

    // The rest is the same as with createMock:
    //   1. Stop recording expected calls.
    //   2. Run code under test.
    //   3. Verify that recorded calls were made.
    replay(foo);
    foo.a();
    verify(foo);
  

我知道我可以编写自己的 Foo 子类来为我做这种事情。但如果我不必这样做,我不想这样做,因为它很乏味,即应该自动化。

【问题讨论】:

【参考方案1】:

在 EasyMock 3.0+ 中,您可以使用 mockbuilder 创建 Partial mock

EasyMock.createMockBuilder(class).addMockedMethod("MethodName").createMock();

【讨论】:

【参考方案2】:

我猜你可以使用 EasyMock 扩展库来做到这一点。你可以在这里找到一个简单的例子Partial Mocking

【讨论】:

谢谢!可悲的是,您似乎需要 Junit 4 才能使用类扩展 :( :easymock.org/EasyMock2_2_ClassExtension_Documentation.html 我想这意味着 Junit 3 用户不走运。 哦......这对我来说也是一个很好的信息......我对你的情况有一个想法......但它不使用简单的模拟,而是通过覆盖方法并返回来自己创建模拟扩展 Mock 类中的模拟 Bar 对象。 从 EasyMock 3.1 开始,ClassExtensions 库已弃用,部分模拟已移至 EasyMock 本身。这表示它适用于 JUnit 3,所以你可能很幸运:easymock.org/EasyMock3_1_Documentation.html【参考方案3】:

OP 似乎(?)暗示子类化比部分模拟更困难或更乏味。我建议值得重新考虑。

例如在测试类中:

  Foo dummyFoo = new Foo() 
      @Override public Bar b()  return new Bar(); 
   ;

与使用 EasyMock 相比,执行 OP 所述的操作,看起来更简单,并且不太容易出现其他问题(忘记重播/验证/等)。

【讨论】:

我不知道你可以用 Java 做到这一点!我猜这是在1.4之后出现的?无论如何,你能用它来创建一个模拟,类似于 jhericks 建议的吗?如果是这样,那就太好了,因为您不必创建一个全新的(子)类来为未测试的方法调用模拟。【参考方案4】:

我会想办法升级到 JUnit 4,并使用类扩展。 (实际上,我会使用 Mockito 而不是 EasyMock,但我们不要重写你的整个测试套件。)如果你不能,那么你总是可以创建自己的间谍:

public class FooTest extends TestCase 
    public static class FooSpy extends Foo 
        private final Fooable mockFoo;

        FooSpy(Fooable mockFoo) 
            this.mockFoo = mockFoo;
        

        public Bar b() 
            return mockFoo.b();
        
    

    public void testA() 
        Fooable mockFoo = createMock(Foo.class);
        Fooable fooSpy = new FooSpy(mockFoo);

        // Foo's implementation of b is not used.
        // Rather, it is replaced with a dummy implementation
        // that records calls that are supposed to be made;
        // and returns a hard coded value (i.e. new Bar()).
        expect(mockFoo.b()).andReturn(new Bar());

        // The rest is the same as with createMock:
        // 1. Stop recording expected calls.
        // 2. Run code under test.
        // 3. Verify that recorded calls were made.
        replay(mockFoo);
        foo.a();
        verify(foo);
    


【讨论】:

这很重要,除非你因为无法使用类扩展而受阻——所以你没有一个框架来为你创建间谍。不过,根据@DoctorRuss 的评论,您可能很幸运。

以上是关于有没有办法使用 EasyMock 部分模拟对象?的主要内容,如果未能解决你的问题,请参考以下文章

是否可以使用 EasyMock 创建一个实现多个接口的模拟对象?

让 EasyMock 模拟对象抛出异常

Powermock(使用 Easymock)没有最后一次调用模拟可用

模拟无效方法的try catch块并使用EasyMock或Mockito捕获异常

EasyMock简单使用方法

如何在easymock中模拟一个返回其参数之一的方法?