Mockito 在看起来没问题的时候给出未完成验证异常

Mockito 似乎在抛出一个 UnfinishedVerificationException,当我认为我所做的一切都是正确的时候:

HttpServletRequest req = mock(HttpServletRequest.class);
when(req.getHeader("Authorization")).thenReturn("foo");


HttpServletResponse res = mock(HttpServletResponse.class);


classUnderTest.doMethod(req, res); // Use the mock


verify(res, never());
verify(req).setAttribute(anyString(), anyObject());

这是部分类和方法:

class ClassUnderTest extends AnotherClass {
@Override
public String doMethod(ServletRequest req, ServletRequest res) {
// etc.
return "someString";
}
}

忽略这样一个事实,即您永远不应该模仿您不拥有的接口,为什么 Mockito 要给我以下信息?

org.mockito.exceptions.misusing.UnfinishedVerificationException:
Missing method call for verify(mock) here:
-> at (redacted)


Example of correct verification:
verify(mock).doSomething()


Also, this error might show up because you verify either of: final/private/equals()/hashCode() methods.
Those methods *cannot* be stubbed/verified.


at [test method name and class redacted]
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at org.junit.runners.model.FrameworkMethod$1.runReflectiveCall(FrameworkMethod.java:47)
at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:12)
at org.junit.runners.model.FrameworkMethod.invokeExplosively(FrameworkMethod.java:44)
at org.junit.internal.runners.statements.InvokeMethod.evaluate(InvokeMethod.java:17)
at org.junit.runners.ParentRunner.runLeaf(ParentRunner.java:271)
at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:70)
at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:50)
at org.junit.runners.ParentRunner$3.run(ParentRunner.java:238)
at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:63)
at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:236)
at org.junit.runners.ParentRunner.access$000(ParentRunner.java:53)
at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:229)
at org.junit.runners.ParentRunner.run(ParentRunner.java:309)
at org.mockito.internal.runners.JUnit45AndHigherRunnerImpl.run(JUnit45AndHigherRunnerImpl.java:37)
at org.mockito.runners.MockitoJUnitRunner.run(MockitoJUnitRunner.java:62)
at org.junit.runner.JUnitCore.run(JUnitCore.java:160)
... etc
66483 次浏览

这是我自己发现的,给我带来了很多困惑。

正如大卫上面提到的,Mockito 报告了在 下一个 Mockito 方法调用中的错误,这些错误可能不在同一个测试方法中。虽然异常消息确实包含了对发生错误的实际位置的引用,但是我发现不正确的测试失败会对测试过程产生反作用。测试越简单,在下一个测试中出现错误的可能性就越大!

这里有一个简单的修复方法,可以确保错误出现在正确的测试方法中:

@After
public void validate() {
validateMockitoUsage();
}

来自 Mockito 文档 给你:

如果您错误地使用它,Mockito 会抛出异常,这样您就可以知道 测试是正确编写的 在下次使用框架 时进行验证(例如, 但是即使异常可能被抛出 在下一个测试中,异常消息包含一个可导航堆栈 跟踪元素的缺陷位置。因此,您可以点击和 找到 Mockito 被滥用的地方。

有时候,你可能会 希望显式地验证框架的使用 用户希望在他的@After 方法中放入 validateMockitoUse () ,因此 当他滥用 Mockito 的时候,他马上就知道了。没有它,他 就会知道这件事 在@After 中使用 validateMockitoUse ()的另一个好处是 JUnit 运行器在测试方法中总是会失败并且有缺陷 而普通的“下一次”验证可能会在下一次测试中失败 但是,即使 JUnit 可能将下一个测试报告为红色,也不要 中的可导航堆栈跟踪元素 异常消息立即找到您误用的位置 小面包。

如果您尝试使用 verify方法,该方法需要使用 any()的基元参数,那么也可能会出现这种情况:

例如,如果我们的方法有这个签名:

method(long l, String s);

如果你试图这样验证它,它会以上述信息失败:

verify(service).method(any(), anyString());

改成 anyLong()就可以了:

verify(service).method(anyLong(), anyString());

类 MyRepository 也有类似的例外

例外: 这里缺少验证(mock)的方法调用: - > 在 MyRepository $$FastClassBySpringCGLIB $$de8d8358.inv()

正确验证的例子:

verify(mock).doSomething()

当我为 MyRepository 和 mock 接口创建接口时,问题得到了解决,但没有实现。 Spring 似乎创建了一些 CGLIB 代理,并导致了 UnfinishedVerificationException 异常。

对我来说,问题是在 test context xml 中缺少 bean 声明。它用于另一个类使用的自定义方面类,该类的实例是类的构造函数的一个参数,该参数用于失败的 validy()调用。因此,我将 bean 声明添加到 context xml 中,在那之后它就工作得很好了。

我也遇到过类似的问题,我找到了解决的办法。模拟您要验证的对象尚未重置,因此您应该重置它。您可以在 重置(模拟)之前测试用例函数,它可能会有所帮助。

我不确定你的“ classUnderTest”是从哪里来的,但是请确保它是 嘲笑不是真的。 对于下面的测试用例,我也有同样的问题:

MyAgent rpc = new MyAgent("myNodeName");
...
rpc.doSomething();
...
PowerMockito.verifyPrivate(rpc).invoke("initPowerSwitch");
PowerMockito.verifyPrivate(rpc).invoke("init", "192.168.0.23", "b2", 3);

但对于下面的测试案例,它消失了:

MyAgent rpc = PowerMockito.spy(new MyAgent("myNodeName"));
...
rpc.doSomething();
...
PowerMockito.verifyPrivate(rpc).invoke("initPowerSwitch");
PowerMockito.verifyPrivate(rpc).invoke("init", "192.168.0.23", "b2", 3);

注意,对象 rpc 应该被 PowerMockito.spit (...)模拟。

使用 Junit5,您可以添加以下内容来在控制台中显示更多有意义的 Mockito 异常

@AfterEach
public void validate() {
validateMockitoUsage()
}

也可以看到这个答案: https://stackoverflow.com/a/22550055/8073652

由于使用带有 boolean参数的 any(),我得到了同样的错误,而显然它需要是 anyBoolean()

如果尝试使用 Mockito.check 验证私有方法或包私有方法,将会得到这个错误。

如果你不想使用 PowerMockito,你可以设置你的方法为 protected,我建议你添加@VisibleForTest 标签:

以前:

void doSomething() {
//Some behaviour
}

之后:

@VisibleForTesting
protected void doSomething() {
//Some behaviour
}

我也犯了同样的错误

org.mockito.exceptions.misusing.UnfinishedVerificationException:
Missing method call for verify(mock) here:
-at com.xxx.MyTest.testRun_Should_xxx_When_yyy(MyTest.java:127)


Example of correct verification:
verify(mock).doSomething()


Also, this error might show up because you verify either of: final/private/equals()/hashCode() methods.
Those methods *cannot* be stubbed/verified.
Mocking methods declared on non-public parent classes is not supported.




at com.xxx.MyTest.validate(MyTest.java:132)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:498)
at org.junit.internal.runners.MethodRoadie.runAfters(MethodRoadie.java:145)
at org.junit.internal.runners.MethodRoadie.runBeforesThenTestThenAfters(MethodRoadie.java:99)
...

在我的例子中,产生错误是因为我在调用 Mockito 核实一下之前使用了 Verifystatic (),然后我必须将 Verifystatic ()移动到最后一行(或者删除它)。

来自:

PowerMockito.verifyStatic();
Mockito.verify(myMock, Mockito.times(1)).myMockedMethod(anyString(), anyString(), anyString(), any(XXX.class), any(YYY.class), any(ZZZ.class));

致:

Mockito.verify(myMock, Mockito.times(1)).myMockedMethod(anyString(), anyString(), anyString(), any(XXX.class), any(YYY.class), any(ZZZ.class));
PowerMockito.verifyStatic();

以上两个答案建议在每次测试后使用 validateMockitoUsage()方法。

虽然这是正确的,但我发现用 @ExtendWith(MockitoExtension.class)注释你的类 在 Junit5中给出了相同的效果,同时添加了一些漂亮的 Mockito 功能。而且,我看起来也更干净。

我想 Junit4@RunWith(MockitoJUnitRunner.class)会给出类似的结果,但我没有测试它。

在我的例子中,使用 Kotlin是因为要测试的函数没有声明为 open

异常注意到不能使用 final/private/equals/hash 方法。

fun increment(){
i++
}

open fun increment(){
i++
}

改成 @RunWith(PowerMockRunner.class)问题就解决了。 之前在使用 @RunWith(MockitoJUnitRunner.class)

希望这对谁有帮助。

我也有同样的问题,在以下堆栈中:

  • 科特林
  • 基地 4.13
  • Mockito 2.28.2 + Mockito-Inline 2.13.0
  • 机器电子 4.3.1

我试图核实一个 Lambda 电话:

@RunWith(RobolectricTestRunner::class)
class MainViewTest {


@get:Rule
val mockitoRule: MockitoRule = MockitoJUnit.rule()


@Mock private lateinit var mockClickCallback: () -> Unit


@Test
fun `should call clickCallback on the button click`() {
val activity = Robolectric.buildActivity(MainActivity::class.java).create().get()
val viewUnderTest = MainView(activity)
viewUnderTest.setClickCallback(mockClickCallback)


viewUnderTest.button.performClick()


verify(mockClickCallback).invoke() // UnfinishedVerificationException
}
}

然后我在 Github 上找到了 问题,似乎问题出在 Robolectric,我使用了以下变通方法:

@RunWith(RobolectricTestRunner::class)
class MainViewTest {


private interface UnitFunction: () -> Unit


@Test
fun `should call clickCallback on the button click`() {
val activity = Robolectric.buildActivity(MainActivity::class.java).create().get()
val viewUnderTest = MainView(activity)
val mockClickCallback = mock(UnitFunction::class.java) as () -> Unit
viewUnderTest.setClickCallback(mockClickCallback)


viewUnderTest.button.performClick()


verify(mockClickCallback).invoke() // OK
}
}

这些测试单独运行得很好,但是在运行集成测试套件时,由于 UnfinishedVerificationException 而失败。问题出现在我们使用来自嘲讽的 valid()和@EnableRetry 时。 解决这个问题的方法是使用

public static <T> T unwrapAndVerify(T mock, VerificationMode mode) {
return ((T) Mockito.verify(AopTestUtils.getTargetObject(mock), mode));
}

正如 在方法上具有@Retryable 注释的模拟 Spring@Service 因 UnfinishedVerificationException 而失败中提到的

这就是我的疑点! 我发现 莫基托Hibernate 验证之间存在冲突。 我的解决方案是将契约检查(@NotNull,@NotEmpty 等)与仿真测试分开。我还开始使用 validateMockitoUsage()来确保正确运行所有程序。

面对同样的例外情况时,使用仿静态方法,并调用 Mockito.check 多次,但通过接口而不是实现类。

错误代码:

try (MockedStatic<Service> staticMock = Mockito.mockStatic(Service.class, Mockito.CALLS_REAL_METHODS)) {
staticMock.verify(() -> ServiceImpl.method()); // passed without errors
staticMock.verify(() -> ServiceImpl.method()); // throws UnfinishedVerificationException
}

固定代码:

try (MockedStatic<ServiceImpl> staticMock = Mockito.mockStatic(Service.class, Mockito.CALLS_REAL_METHODS)) {
staticMock.verify(() -> ServiceImpl.method());
staticMock.verify(() -> ServiceImpl.method());
}

这显然是我的错误,但未完成验证异常消息没有帮助