Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/java/378.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Java Mockito在final方法中调用实际代码,而不是抛出MissingMethodInvocationException_Java_Testing_Mocking_Mockito_Final - Fatal编程技术网

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
methodwith
if
),有时它抛出
MissingMethodInvocationException
foo
methodwith
if
)。被测试的方法是
final
这一事实是一个错误。我发现Mockito抛出异常非常令人不安,在某些情况下,最终的方法被模拟,而在另一些情况下,实际代码被静默地执行。我宁愿在每次模拟最终方法时都看到一个异常。我不希望在mock上调用真正的代码。当方法是final时,您或Mockito无法阻止真正的代码被执行,JVM将始终调用final方法。i、 e
foo.foo()
将始终调用实方法,因为Mockito根本无法存根
foo