Java Mockito在final方法中调用实际代码,而不是抛出MissingMethodInvocationException
在下面的代码中,我希望Java Mockito在final方法中调用实际代码,而不是抛出MissingMethodInvocationException,java,testing,mocking,mockito,final,Java,Testing,Mocking,Mockito,Final,在下面的代码中,我希望given将抛出MissingMethodInvocationException,因为foo()是最终的 但是相反,我在str.equals(“字符串1”) 所以,Mockito正在调用真正的代码。为什么? import static org.junit.Assert.assertEquals; import static org.mockito.BDDMockito.given; import org.junit.Test; import org.junit.runne
given
将抛出MissingMethodInvocationException
,因为foo()
是最终的
但是相反,我在str.equals(“字符串1”)
所以,Mockito正在调用真正的代码。为什么?
import static org.junit.Assert.assertEquals;
import static org.mockito.BDDMockito.given;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.Mock;
import org.mockito.runners.MockitoJUnitRunner;
class Foo {
private String str = "String 1";
public final String foo() {
if (str.equals("String 1")) {
str = "String 2";
}
return str;
}
}
@RunWith(MockitoJUnitRunner.class)
public class TestClass {
@Mock
Foo foo;
@Test
public void test() {
given(foo.foo()).willReturn("x");
assertEquals("x", foo.foo());
}
}
在下面的示例中,我删除了if子句。现在它可以按预期工作。当然,我不想删除这些行,因为我正在测试的代码中需要它们。
这些线条的存在如何影响Mockito的行为
public final String foo() {
return str;
}
我如何确保Mockito永远不会调用方法上的真正代码,即使它们碰巧是最终的?我宁愿看到
MissingMethodInvocationException
在此代码中,测试通过:
public String foo() {
if (str.equals("String 1")) {
str = "String 2";
}
return str;
}
我询问的原因是,我有一个测试用例,有人将final
修饰符添加到正在测试/模拟的方法之一。我们没有看到
MissingMethodInvocationException
,而是看到模拟方法中的“真实”代码引发了一些不相关的异常。我们花了一些时间寻找导致测试失败的地方和变化。如果Mockito抛出
MissingMethodInvocationException
,我们会立即看到原因。您可以使用
另见tl;dr:Mockito无法模拟最终方法。它也无法检测到正在调用的最终方法 更详细的解释:这是Java期末考试的缺点之一。您唯一的选择是使用Powermock,尽管我将保留对遗留代码的使用 Mockito的问题是,它通过将类型子类化为mock来工作,Java编译器或JVM不允许任何将最终类子类化或重写最终方法的操作。Mockito不能用我们目前的设计在这方面做任何事情
然而,漂亮的Powermock添加了另一个步骤,在另一个类加载器中重新加载类,执行一些修改,特别是删除要模拟的类型中的最终标志。尽管这种方法也有缺点:测试中的配置越多,测试消耗的Permgen就越大,测试的启动速度就越慢。请参见我的编辑。我们不希望这个方法是最终的。这是一个错误。但Mockito并没有通过抛出
MissingMethodInvocationException
试图模拟final方法来帮助我们找到它。相反,它执行真正的代码。这就是问题所在。所以你真正想要的是列出所有在测试中调用的最终模拟方法?我想要的是避免在模拟上调用真正的代码,以防有人错误地将最终修饰符添加到方法中。我决不会假设一个mock在任何情况下都会调用真正的代码。我错了。现在我想知道Mockito为什么要这样做。当使用@Mock注释时,Mock类的私有字段没有初始化。因此'str'是空的,并且从未设置为“string1”,这解释了NPEYes,我知道了。但是如何解释调用实际方法foo()
?这就是我要问的。调用given
模拟最终方法。为什么Mockito在执行真正的代码,而不是抱怨最终的方法被模拟?好的,我可以看到Mockito在最终的方法上不起作用。但我不明白为什么它在某些情况下调用真正的代码(foo
methodwithif
),有时它抛出MissingMethodInvocationException
(foo
methodwithif
)。被测试的方法是final
这一事实是一个错误。我发现Mockito抛出异常非常令人不安,在某些情况下,最终的方法被模拟,而在另一些情况下,实际代码被静默地执行。我宁愿在每次模拟最终方法时都看到一个异常。我不希望在mock上调用真正的代码。当方法是final时,您或Mockito无法阻止真正的代码被执行,JVM将始终调用final方法。i、 efoo.foo()
将始终调用实方法,因为Mockito根本无法存根foo
。