Java 有什么方法可以取代动态方法吗?

Java 有什么方法可以取代动态方法吗?,java,unit-testing,junit,easymock,powermock,Java,Unit Testing,Junit,Easymock,Powermock,假设我们有一个接口,它有两种方法: public interface MyInterface { public SomeType first(); public SomeType second(); } 此接口由MyInterfaceImpl实现。在实现内部,first()调用second()来检索一些结果 我想构建一个单元测试,它将根据从second()中得到的内容断言从first()中得到的内容,类似于: 1 public class MyInterfaceTest {

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

public interface MyInterface {
    public SomeType first();
    public SomeType second();
}
此接口由
MyInterfaceImpl
实现。在实现内部,
first()
调用
second()
来检索一些结果

我想构建一个单元测试,它将根据从
second()
中得到的内容断言从
first()
中得到的内容,类似于:

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
行上创建一个mock,这样所有对所选方法的调用(例如
first()
)都将被直接调用(委托给
MyInterfaceImpl
),而其他一些方法(例如
second()
)将被替换为mock对等方法

对于静态方法,这实际上非常容易使用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
实际上取决于其他模拟


我希望这样的事情由一个框架来处理,而不是由我自己的类来处理。这是可以实现的吗?

听起来,如果
first()
的实现必须调用
second()
,那么您很可能应该为
first()
second()
提供单独的接口。然后也可以拆分实现,并在测试
first()
时模拟
second()
。如果没有一个更具体的例子来说明
first()
second()
是什么,那么很难说清楚

在实现类上使用EasyMock仅模拟
second()
调用可能会起作用,但您似乎并不想这样做。这可能需要告诉EasyMock将对
first()
的调用传递到正常实现-我不确定

另一个选项可能是在测试类中对实现进行子类化(作为嵌套类),从而允许您仅覆盖
second()
,以进行测试。不过它很难看


就我个人而言,我不喜欢为了测试其他部分而假装出一节课的一部分。我更愿意冒充类的所有依赖项。

听起来,如果
first()
的实现必须调用
second()
,那么
first()和
second()应该有单独的接口。然后也可以拆分实现,并在测试
first()
时模拟
second()
。如果没有一个更具体的例子来说明
first()
second()
是什么,那么很难说清楚

在实现类上使用EasyMock仅模拟
second()
调用可能会起作用,但您似乎并不想这样做。这可能需要告诉EasyMock将对
first()
的调用传递到正常实现-我不确定

另一个选项可能是在测试类中对实现进行子类化(作为嵌套类),从而允许您仅覆盖
second()
,以进行测试。不过它很难看


就我个人而言,我不喜欢为了测试其他部分而假装出一节课的一部分。我宁愿伪造所有类的依赖项。

可能您可以使用。

可能您可以使用。

好的旧子类化如何?我是说

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中可以正常工作

好的旧子类怎么样?我是说

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中可以正常工作

不幸的是,拆分first()和second()不是一个选项——我们的设计以业务逻辑类型为中心,其思想是将所有为该类型工作的函数保持在同一屋檐下。谢谢你的回答。@mindas:我鼓励你至少重新考虑这个决定。例如,帐户验证器不应与帐户报告生成器的类型相同。如果你被难看的设计决策所束缚,那么当测试(和实现)变得难看时,你不应该感到惊讶:((当然,这是假设它真的是一个难看的设计。我在猜测,但听起来像是…)这有点离题,但你真的建议方法不应该使用同一类的其他公共方法吗?例如,在Java String.equalsIgnoreCase调用String.regionMatches中-虽然这些函数不同,但它们没有那么大的不同,可以单独放置。从字符串不是in的角度来看,这可能是一个坏例子terface但我想指出的是,我的情况非常相似,所以first()和second()做得非常接近不是一个选项-我们的设计是以业务逻辑类型为中心的,我们的想法是将为该类型工作的所有功能保持在同一屋檐下。不过谢谢你的回答。@mindas:我鼓励你至少重新考虑这个决定。例如,帐户验证器不应该与帐户报告生成器的类型相同e、 如果你被难看的设计决策所束缚,那么当测试(和实现)变得难看时,你不应该感到惊讶:((当然,这是假设它真的是一个难看的设计。我在猜测,但听起来像是…)这有点离题,但你真的建议方法不应该使用同一类的其他公共方法吗?例如,在Java String.equalsIgnoreCase调用String.regionMatches中-虽然这些函数不同,但它们没有那么大的不同,可以单独放置。从字符串不是in的角度来看,这可能是一个坏例子但我想指出的是,我的情况非常相似,所以first()和second()做了一件非常接近的事情。非常有趣的建议。但是它不适用于这里