Mockito在final方法中调用实际代码,而不是抛出MissingMethodInvocationException



在下面的代码中,我预计given将抛出MissingMethodInvocationException,因为foo()是最终的。

但是我在str.equals("String 1")得到NullPointerException
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不能模拟final方法。而且它也不能检测到正在调用的final方法。

更长的解释:这是Java中final的缺点之一。唯一的选择是使用Powermock,尽管我将保留对遗留代码的使用。

Mockito的问题是,它通过子类化要模拟的类型来工作,Java编译器或JVM不允许任何继承final类或重写final方法的东西。Mockito不能在我们目前的设计上做任何事情。

而Powermock添加了另一个步骤,在另一个类加载器中重新加载类,执行一些修改,特别是删除要模拟的类型中的final标志。尽管这种方法也有缺点:测试中的配置更多,测试消耗更多的Permgen,测试启动速度较慢。

可以使用PowerMock

参见Powermockito可以模拟非final具体类中的final方法吗?

相关内容

  • 没有找到相关文章

最新更新