Java 最终方法模拟
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/3793791/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Final method mocking
提问by Stan Kurilin
I need mock some class with final method using mockito. I have wrote something like this
我需要使用 mockito 用 final 方法模拟一些类。我写过这样的东西
@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";
}
}
But it fails. I tried some "hack" and it works.
但它失败了。我尝试了一些“hack”并且它有效。
@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());
}
It works, but "smells".
它有效,但“闻起来”。
So, Where is the right way?
那么,正确的方法在哪里?
Thanks.
谢谢。
采纳答案by iwein
There is no support for mocking final methods in Mockito.
Mockito 中不支持模拟 final 方法。
As Jon Skeet commented you should be looking for a way to avoid the dependency on the final method. That said, there are some ways out through bytecode manipulation (e.g. with PowerMock)
正如 Jon Skeet 评论的那样,您应该寻找一种方法来避免对最终方法的依赖。也就是说,有一些方法可以通过字节码操作(例如使用 PowerMock)
A comparison between Mockito and PowerMockwill explain things in detail.
Mockito 和 PowerMock 之间的比较将详细说明事情。
回答by matt b
From the Mockito FAQ:
What are the limitations of Mockito
- Cannot mock final methods - their real behavior is executed without any exception. Mockito cannot warn you about mocking final methods so be vigilant.
Mockito 的局限性是什么
- 无法模拟 final 方法 - 它们的真实行为毫无例外地执行。Mockito 不能警告你嘲笑 final 方法,所以要保持警惕。
回答by Justin Rowe
You can use Powermock together with Mockito, then you do not need to subclass B.class. Just add this to the top of your test class
您可以将 Powermock 与 Mockito 一起使用,那么您不需要子类化 B.class。只需将此添加到测试类的顶部
@RunWith(PowerMockRunner.class)
@PrepareForTest(B.class)
@PrepareForTest
instructs Powermock to instrument B.class to make the final and static methods mockable. A disadvantage of this approach is that you must use PowerMockRunner which precludes use of other test runners such as the Spring test runner.
@PrepareForTest
指示 Powermock 检测 B.class 以使 final 和静态方法可模拟。这种方法的一个缺点是您必须使用 PowerMockRunner,这会阻止使用其他测试运行器,例如 Spring 测试运行器。
回答by Bill K
I just did this same thing. My case was that I wanted to ensure the method didn't "Cause" an error but since it's a catch/log/return method I couldn't test for it directly without modifying the class.
我只是做了同样的事情。我的情况是我想确保该方法不会“导致”错误,但由于它是一个 catch/log/return 方法,我无法在不修改类的情况下直接测试它。
I wanted to simply mock the logger I passed in, but something about mocking the "Log" interface didn't seem to work and Mocking a class like "SimpleLog" didn't work because those methods are final.
我想简单地模拟我传入的记录器,但是模拟“Log”接口的一些东西似乎不起作用,模拟“SimpleLog”之类的类不起作用,因为这些方法是最终的。
I ended up creating an anonymous inner class extending SimpleLog that overrid the base-level "log(level, string, error)" method that the others all delegate to, then just waiting for a call with a "level" of 5.
我最终创建了一个匿名内部类,扩展了 SimpleLog,它覆盖了其他人都委托给的基本级别的“日志(级别,字符串,错误)”方法,然后只等待“级别”为 5 的调用。
In general, extending a class for behavior isn't really a bad idea, might be preferable to mocking anyway if it's not too complicated.
一般来说,为行为扩展一个类并不是一个坏主意,如果它不太复杂,可能比模拟更可取。
回答by WindRider
Mockito 2 now supports mocking final methods but that's an "incubating" feature. It requires some steps to activate it which are described here: https://github.com/mockito/mockito/wiki/What's-new-in-Mockito-2#mock-the-unmockable-opt-in-mocking-of-final-classesmethods
Mockito 2 现在支持模拟最终方法,但这是一个“孵化”功能。它需要一些步骤来激活它,这里描述:https: //github.com/mockito/mockito/wiki/What's-new-in-Mockito-2#mock-the-unmockable-opt-in-mocking-of-期末班方法
回答by Murtuza Mithaiwala
Assuming that B class is as below:
假设B类如下:
class B {
private String barValue;
public final String bar() {
return barValue;
}
public void final setBar(String barValue) {
this.barValue = barValue;
}
}
There is a better way to do this without using PowerMockito framework. You can create a SPY for your class and can mock your final method. Below is the way to do it:
有一种更好的方法可以在不使用 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());
}
回答by Cypress Frankenfeld
Mockito 2.x now supports final method and final class stubbing.
Mockito 2.x 现在支持 final 方法和 final 类存根。
从文档:
Mocking of final classes and methods is an incubating, opt-in feature. This feature has to be explicitly activated by creating the file
src/test/resources/mockito-extensions/org.mockito.plugins.MockMaker
containing a single line:
mock-maker-inline
After you create this file you can do:
final class FinalClass { final String finalMethod() { return "something"; } } FinalClass concrete = new FinalClass(); FinalClass mock = mock(FinalClass.class); given(mock.finalMethod()).willReturn("not anymore"); assertThat(mock.finalMethod()).isNotEqualTo(concrete.finalMethod());
In subsequent milestones, the team will bring a programmatic way of using this feature. We will identify and provide support for all unmockable scenarios.
模拟 final 类和方法是一个孵化的、可选的功能。必须通过创建
src/test/resources/mockito-extensions/org.mockito.plugins.MockMaker
包含一行的文件来显式激活此功能:
mock-maker-inline
创建此文件后,您可以执行以下操作:
final class FinalClass { final String finalMethod() { return "something"; } } FinalClass concrete = new FinalClass(); FinalClass mock = mock(FinalClass.class); given(mock.finalMethod()).willReturn("not anymore"); assertThat(mock.finalMethod()).isNotEqualTo(concrete.finalMethod());
在随后的里程碑中,团队将带来使用此功能的编程方式。我们将识别所有不可模拟的场景并提供支持。