【问题标题】:Can I mock a super class method call?我可以模拟超类方法调用吗?
【发布时间】:2010-10-11 23:41:39
【问题描述】:

有时,你想测试一个类方法,并且你想对超类方法的调用做一个期望。我没有找到使用easymock或jmock在java中实现这种期望的方法(我认为这是不可能的)。

有一个(相对)干净的解决方案,使用超类方法逻辑创建一个委托,然后对其设置期望,但我不知道为什么以及何时使用该解决方案¿任何想法/示例?

谢谢

【问题讨论】:

  • 我想不出一个真正令人信服的理由来说明这是一个坏主意。 +1 精彩的问题。

标签: java tdd mocking easymock jmock


【解决方案1】:

好吧,如果你愿意,你可以。不知道大家是否熟悉JMockit,去看看吧。当前版本是0.999.17,同时,我们来看看吧……

假设以下类层次结构:

public class Bar {
    public void bar() {
        System.out.println("Bar#bar()");
    }
}

public class Foo extends Bar {
    public void bar() {
        super.bar();
        System.out.println("Foo#bar()");
    }
}

然后,在您的 FooTest.java 中使用 JMockit,您可以验证您实际上是在从 Foo 调用 Bar

@MockClass(realClass = Bar.class)
public static class MockBar {
    private boolean barCalled = false;

    @Mock
    public void bar() {
        this.barCalled = true;
        System.out.println("mocked bar");
    }
}

@Test
public void barShouldCallSuperBar() {
    MockBar mockBar = new MockBar();
    Mockit.setUpMock(Bar.class, mockBar);

    Foo foo = new Foo();
    foo.bar();

    Assert.assertTrue(mockBar.barCalled);

    Mockit.tearDownMocks();
}

【讨论】:

【解决方案2】:

使用 JMockit 1.22 扩展 @Cem Catikkas 答案:

@Test
public void barShouldCallSuperBar() {
    new MockUp<Bar>() {
        @Mock
        public void bar() {
            barCalled = true;
            System.out.println("mocked bar");
        }
    };

    Foo foo = new Foo();
    foo.bar();

    Assert.assertTrue(mockBar.barCalled);
}

不需要@MockClass注解的静态类,用MockUp类代替。

【讨论】:

    【解决方案3】:

    我不认为我会模拟一个超级调用 - 我觉得这种行为是类本身行为的一部分,而不是依赖项的行为。 Mocking 总是感觉它应该与依赖关系比其他任何事情都更重要。

    你有一个很好的例子来说明你想模拟的那种调用吗?如果您想模拟这样的调用,是否值得考虑组合而不是继承?

    【讨论】:

    • 是的,但是你想测试隔离的子类,你知道超类工作正常,你不想再测试它。
    • 请不要这样做。您正在打破封装以将实现锁定到测试中。除非此代码不再更改,否则您会后悔的。
    【解决方案4】:

    在 Animated Transitions 示例测试套件中,有几个使用 JMockit 期望 API 的测试可以做到这一点(即指定超类方法的预期调用)。例如,FadeInTest 测试用例。

    【解决方案5】:

    不,没有办法用jMock 模拟超类方法。

    但是,对于您的问题,有一个快速而简单的解决方案。假设您有 A 类和 B 类扩展 A。您想在 B 上模拟方法 Aa()。您可以在测试代码中引入 C 类扩展 B 并覆盖方法 Ca()(只需调用 super,或返回 null、id没关系)。在那个模拟 C 之后,在你可以使用 B 的任何地方使用这个模拟。

    【讨论】:

    • 没有那么脏。我们可以在测试类中创建 C 类作为内部类。
    • 如果你调用同名的超级方法,这实际上是行不通的。 B.a() 调用 A.a()。如果你引入 C.a() 并调用 super,你最终会得到 C.a() -> B.a() -> A.a()
    【解决方案6】:

    拦截超级调用过于细粒度。不要过度隔离。

    【讨论】:

      猜你喜欢
      • 2011-11-29
      • 1970-01-01
      • 1970-01-01
      • 2011-11-30
      • 1970-01-01
      • 1970-01-01
      • 2012-04-14
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多