最终方法嘲弄

我需要模拟一些类与最终方法使用模拟。我已经写了这样的东西

@Test
public void test() {
B b = mock(B.class);
doReturn("bar called").when(b).bar();
assertEquals("must be \"overrided\"", "bar called", b.bar());
//bla-bla
}




class B {
public final String bar() {
return "fail";
}
}

但是失败了。 我尝试了一些“黑客”,它的工作。

   @Test
public void hackTest() {
class NewB extends B {
public String barForTest() {
return bar();
}
}
NewB b = mock(NewB.class);
doReturn("bar called").when(b).barForTest();
assertEquals("must be \"overrided\"", "bar called", b.barForTest());
}

有用,但是有“气味”。

那么,正确的路在哪里?

谢谢。

83096 次浏览

在 Mockito 没有嘲笑最终方法的支持。

正如 Jon Skeet 所说,您应该寻找一种方法来避免对最终方法的依赖。也就是说,有一些方法可以解决字节码操作问题(例如 PowerMock)

Mockito 与 PowerMock 的比较将详细解释事情。

来自 Mockito 常见问题解答:

Mockito 的局限是什么

  • 不能模仿 final 方法——它们的实际行为将毫无例外地执行。Mockito 不能警告你嘲笑最终的方法,所以要保持警惕。

你可以和 Mockito 一起使用 Powermock,这样你就不需要子类 B 了。只需要将它添加到测试类的顶部

@RunWith(PowerMockRunner.class)
@PrepareForTest(B.class)

@PrepareForTest指示 Powermock 使用工具 B 类来模拟最终的和静态的方法。这种方法的一个缺点是您必须使用 PowerMockRunner,它排除了使用其他测试运行程序,如 Spring 测试运行程序。

我刚做了同样的事。我的情况是,我希望确保该方法不会导致错误。但是,因为它是 catch/log/return 方法,所以如果不修改类,就不能直接测试它。

我只是想嘲笑我进去的那个伐木工。但是,关于模仿 Log接口的一些东西似乎不起作用,模仿像 SimpleLog这样的类也不起作用,因为这些方法都是最终的。

最后,我创建了一个扩展 SimpleLog的匿名内部类,它覆盖了其他所有委托的基本级 log(level, string, error)方法。然后测试就是等待一个 level为5的电话。

一般来说,为行为扩展一个类并不是一个坏主意,如果不是太复杂的话,可能比嘲笑更好。

Mockito 2现在支持模拟最终方法,但这是一个“孵化”特性。它需要一些步骤来激活它,这里描述: Https://github.com/mockito/mockito/wiki/what’s-new-in-mockito-2#mock-the-unmockable-opt-in-mocking-of-final-classesmethods

假设 B 类如下:

class B {
private String barValue;
public final String bar() {
return barValue;
}
public void final setBar(String barValue) {
this.barValue = barValue;
}
}

有一种不使用 PowerMockito 框架的更好方法可以做到这一点。 您可以为您的类创建一个 SPY,并且可以模拟您的最终方法。 下面是做到这一点的方法:

@Test
public void test() {


B b  = new B();
b.setBar("bar called") //This should the expected output:final_method_bar()
B spyB = Mockito.spy(b);
assertEquals("bar called", spyB.bar());


}

Mockito 可以用来模拟最终类或最终方法。问题是,这个特性并不是 Mockito 提供的,需要进行显式的配置。

所以,为了达到这个目的,

创建一个名为 org.mockito.plugins.MockMaker的文本文件到项目的 src/test/resources/mockito-extensions目录,并添加一行文本,如下所示

mock-maker-inline

一旦完成,您可以使用模仿的 什么时候方法来模仿的行为,就像任何其他常规方法。

参见详细的例子 给你