使用EasyMock是否有一种部分模拟对象的方法?

14

例如,假设我有这个类:

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子类来完成这种操作。但如果不必要,我不想这样做,因为这很乏味, 应该是可以自动化的。

4个回答

16
在EasyMock 3.0+中,您可以使用mockbuilder创建Partial mock。mockbuilder
EasyMock.createMockBuilder(class).addMockedMethod("MethodName").createMock();

3

我想你可以使用EasyMock扩展库来完成这个任务。在这个Partial Mocking示例中,你可以找到一个简单的例子。


谢谢!不幸的是,似乎您需要 Junit 4 才能使用 classextensions :( : http://easymock.org/EasyMock2_2_ClassExtension_Documentation.html 我猜这意味着 Junit 3 用户没有机会了。 - allyourcode
哦...这对我也是一个好消息...我对你的情况有一些想法...但不是使用 Easy Mock,而是通过覆盖方法创建自己的模拟对象,并从扩展的 Mock 类返回您的模拟 Bar 对象。 - raddykrish
2
从EasyMock 3.1开始,ClassExtensions库已被弃用,并且部分模拟已移入EasyMock本身。这意味着它可以与JUnit 3一起使用,所以你可能很幸运:http://easymock.org/EasyMock3_1_Documentation.html - DoctorRuss

2

这篇文章似乎在暗示子类化比部分模拟更加困难或繁琐。我建议重新思考一下。

例如,在测试类中:

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

OP所述的功能似乎更简单,且不易出现其他问题(例如忘记重放/验证等),比使用EasyMock更可靠。


1
我不知道Java可以做到这一点!我猜这是在1.4之后出现的吧?无论如何,你能用它来创建一个模拟对象,类似于jhericks建议的那样吗?如果可以的话,那就太棒了,因为你就不必再创建一个全新的(子)类来调用未经测试的方法了。 - allyourcode

1

我会找到一种升级到JUnit 4并使用类扩展的方法。(实际上,我会使用Mockito而不是EasyMock,但我们不需要重写你的整个测试套件。)如果你不能这样做,那么你总可以像这样创建自己的spy:

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的评论,看起来你运气不错。 - jhericks

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接