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

时间:2014-07-04 10:15:18

标签: java testing mocking mockito final

在下面的代码中,我希望givenMissingMethodInvocationException投放foo(),因为NullPointerException是最终的。

但我在str.equals("String 1")得到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()); } } 所以,Mockito正在调用真正的代码。为什么呢?

    public final String foo() {
        return str;
    }

在下面的示例中,我删除了if子句。现在它按预期工作。
当然,我不想删除那些在我测试的代码中需要的行。
这些线条的存在如何影响Mockito的行为?

MissingMethodInvocationException

我怎样才能确保Mockito永远不会在方法上调用真正的代码,即使它们恰好是最终的? 我宁愿看 public String foo() { if (str.equals("String 1")) { str = "String 2"; } return str; }

在此代码中,测试通过:

final

我问的原因是我有一个测试用例并且有人将MissingMethodInvocationException修饰符添加到正在测试/模拟的方法之一。
我们没有看到MissingMethodInvocationException,而是看到了一些与“真实”无关的例外情况。模拟方法中的代码。我们花了一些时间寻找导致测试失败的地方和变化 如果Mockito投掷{{1}},我们会立即看到原因。

2 个答案:

答案 0 :(得分:3)

tl; dr :Mockito无法模拟最终方法。并且它无法检测到被调用的最终方法。

更长的解释:这是Java决赛的一个缺点。你唯一的选择是使用Powermock,尽管我会继续使用Powermock。

Mockito的作用是它通过将类型子类化为mock来工作,而Java编译器或JVM只是不允许任何子类化最终类或覆盖最终方法的东西。 Mockito对我们目前的设计无能为力。

而漂亮的Powermock又添加了另一个步骤,在另一个类加载器中重新加载类,执行多个修改,特别是删除类型中的最终标志以进行模拟。虽然这种方法也有缺点:测试中的配置越多,测试消耗的Permgen就越多,测试速度越慢。

答案 1 :(得分:0)