有什么办法可以替代动态方法吗?

发布于 2024-10-27 22:59:20 字数 1331 浏览 7 评论 0原文

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

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 行上创建一个模拟,以便直接调用对选定方法(例如 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 实际上取决于其他模拟。

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

Let's say we have an interface which has two methods:

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

This interface is implemented by MyInterfaceImpl. Inside the implementation, first() calls second() to retrieve some results.

I want to build a unit test which would assert things coming out of first() based on what comes out of second(), similar to:

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 }

Is there an easy way to create a mock on the line 2 so that all calls to selected methods (e.g. first()) would be invoked directly (delegated to MyInterfaceImpl) whereas some other methods (e.g. second()) replaced with mock counterparts?

This is actually very easily doable with PowerMock for static methods, but I need something similar for dynamic ones.

Solutions based on

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();

are not good enough, especially for interfaces having lots of methods (lots of boilerplate). I need the forwarding behaviour as real actually depends on other mocks.

I would expect something like this to be handled by a framework, and not by my own class. Is this achievable?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

也只是曾经 2024-11-03 22:59:20

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

在实现类上使用 EasyMock 来模拟 second() 调用可能有效,但您似乎无论如何都不想这样做。这可能需要告诉EasyMock将对first()的调用传递给正常的实现 - 我不确定。

另一种选择可能是在测试类中对实现进行子类化(作为嵌套类),从而允许您出于测试目的仅重写 second() 。虽然它非常丑陋。

就我个人而言,我不喜欢仅仅为了测试其余部分而伪造课程的部分。我宁愿伪造一个类的所有依赖项。

It sounds like you should quite possibly have separate interfaces for first() and second(), if the implementation of first() has to call second(). You could then split the implementation too, and mock out second() while testing first(). Without a more concrete example of what first() and second() are, it's tricky to say for sure.

Using EasyMock on the implementation class to mock out only second() call might work, but you don't seem to want to do that anyway. This may require telling EasyMock to pass calls to first() through to the normal implementation - I'm not sure.

Another option might be to subclass the implementation within the test class (as a nested class) allowing you to override just second() for the purposes of testing. It's pretty ugly though.

Personally I don't like faking out part of a class just to test the rest. I'd much rather fake out all a class's dependencies.

虐人心 2024-11-03 22:59:20

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

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 中工作正常。;-)

How about good old subclassing? I mean something like

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(...);
}

You are not testing the exact class you want to test, but an anonymous subclass. But we can assume subclassing works ok in Java.;-)

屋檐 2024-11-03 22:59:20

也许您可以使用动态代理

Possibly you could use a Dynamic Proxy.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文