有没有办法替换动态方法?

时间:2011-03-29 16:34:11

标签: java unit-testing junit easymock powermock

假设我们有一个接口有两种方法:

public interface MyInterface {
    public SomeType first();
    public SomeType second();
}

此界面由MyInterfaceImpl实施。在实施过程中,first()调用second()来检索一些结果。

我想构建一个单元测试,根据first()的内容来断言second()的内容,类似于:

1  public class MyInterfaceTest {
2     private MyInterface impl = new MyInterfaceImpl();

4     @Test
5     public void testFirst() {
6         // modify behaviour of .second()
7         impl.first();
8         assertSomething(...);

10        // modify behaviour of .second()
11        impl.first();
12        assertSomethingElse(...);
13    }
14 }

是否有一种简单的方法可以在行2上创建模拟,以便直接调用所有对所选方法的调用(例如first())(委托给MyInterfaceImpl)其他方法(例如second())替换为模拟对应物?

对于静态方法,这实际上非常容易使用PowerMock,但我需要类似动态的方法。

基于

的解决方案
MyInterface mock = EasyMock.createMock(MyInterface.class);
MyInterface real = new MyInterfaceImpl();
EasyMock.expect(mock.first()).andReturn(real.first()).anyTimes();
EasyMock.expect(mock.second()).andReturn(_somethingCustom_).anyTimes();

不够好,特别是对于有很多方法的接口(很多样板)。我需要转发行为,real实际上取决于其他模拟。

我希望这样的东西可以由框架处理,而不是由我自己的类处理。这可以实现吗?

3 个答案:

答案 0 :(得分:2)

如果first()的实现必须调用second(),那么您应该很可能为first()second()设置单独的界面。然后,您可以拆分实现,并在测试second()时模拟first()。如果没有first()second()的更具体的例子,肯定会说它很棘手。

在实现类上使用EasyMock来模拟 second()调用可能工作,但你好像不想这样做。这个可能要求告诉EasyMock将调用传递给first()到正常实施 - 我不确定。

另一种选择可能是在测试类中实现子类化(作为嵌套类),允许您仅为了测试而覆盖second()。它虽然很难看。

就我个人而言,我不想伪造一个班级的部分来测试其余部分。我更愿意假装所有一个类的依赖。

答案 1 :(得分:1)

可能你可以使用Dynamic Proxy

答案 2 :(得分:1)

好老的子类化怎么样?我的意思是

private MyInterface impl = new MyInterfaceImpl(){
    public final MyInterface mock = EasyMock.createMock(MyInterface.class);
    @override //only the method you need to mock
    public SomeType second(){
        return mock.second();        
    }
}

@Test
public void testFirst() {
    // modify behaviour of .second()
    EasyMock.expect(impl.mock.second()).andReturn("What I want").anyTimes();
    impl.first();
    assertSomething(...);

    // modify behaviour of .second()
    EasyMock.expect(impl.mock.second()).andReturn("Now I want something else").anyTimes();
    impl.first();
    assertSomethingElse(...);
}

您没有测试要测试的确切类,而是测试匿名子类。但是我们可以假设子类在Java中工作正常。; - )