我可以模拟超类方法调用吗?
Posted
技术标签:
【中文标题】我可以模拟超类方法调用吗?【英文标题】:Can I mock a super class method call? 【发布时间】:2010-10-11 23:41:39 【问题描述】:有时,你想测试一个类方法,并且你想对超类方法的调用做一个期望。我没有找到使用easymock或jmock在java中实现这种期望的方法(我认为这是不可能的)。
有一个(相对)干净的解决方案,使用超类方法逻辑创建一个委托,然后对其设置期望,但我不知道为什么以及何时使用该解决方案¿任何想法/示例?
谢谢
【问题讨论】:
我想不出一个真正令人信服的理由来说明这是一个坏主意。 +1 精彩的问题。 【参考方案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();
【讨论】:
也可以使用 JMockit Expectations API 来实现(请参阅code.google.com/p/jmockit 的新项目站点)。【参考方案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 测试用例。
【讨论】:
此测试同时移至:code.google.com/p/jmockit/source/browse/trunk/samples/… 再次搬家:github.com/jmockit/jmockit1/blob/master/samples/…【参考方案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】:拦截超级调用过于细粒度。不要过度隔离。
【讨论】:
以上是关于我可以模拟超类方法调用吗?的主要内容,如果未能解决你的问题,请参考以下文章