Mockito将未验证的Mock标记为已验证?JUnit5测试异常问询
我在JUnit5测试中使用Mockito.verifyNoMoreInteractions(mock1, mock2, ...)方法,近期发现该方法无法检测出未验证的Mock调用——明明我忘记编写对应的verify()语句。
调试时通过Mockito.mockingDetails(mock).getInvocations()查看Mock的调用记录,意外发现Mock方法被调用后,对应的调用记录的verified字段直接被设为true,导致verifyNoMoreInteractions()无法识别这些未显式验证的调用。
我原本认为所有Mock调用都需要通过显式的verify()调用标记为已验证,想知道是我的理解有误,还是Mockito存在问题?
附上本应失败却运行通过的测试类:
@ExtendWith(MockitoExtension.class) class UserManagerTest { UserManager userManager; @Mock DataNetworkPlugin dataNetworkPlugin; @Mock Source source; @BeforeEach void setUp() { initializeTest(); } @AfterEach void tearDown() { verifyNoMoreInteractions(source, dataNetworkPlugin); } @Test void test() { System.out.println("test"); } private void initializeTest() { when(dataNetworkPlugin.getElement(anyString())).thenReturn(source); when(source.asDataSource()).thenReturn(null); userManager = UserManager.createInstance(dataNetworkPlugin); } }
注:dataNetworkPlugin.getElement("")和source.asDataSource()均在UserManager.createInstance()内部被调用。
更新2:修改tearDown方法后测试仍能运行,Mockito未提示过度验证:
@AfterEach void tearDown() { verify(source).asDataSource(); verify(dataNetworkPlugin).getElement(); verifyNoMoreInteractions(source, dataNetworkPlugin); }
这是因为Mockito默认会将when()存根时触发的调用自动标记为已验证。
在你的测试代码中,initializeTest()方法里调用when(dataNetworkPlugin.getElement(anyString()))时,Mockito的存根语法会实际执行一次dataNetworkPlugin.getElement()的Mock方法调用——这是when().thenReturn()语法的固有特性。同理,when(source.asDataSource()).thenReturn(null)也会触发一次source.asDataSource()的调用。这些存根阶段产生的调用,会被Mockito自动标记为verified=true,所以后续的verifyNoMoreInteractions()会直接忽略它们。
你的理解偏差在于:并非所有Mock调用都需要显式的verify()验证,Mockito对存根过程中产生的调用会自动“豁免”验证。
如果想要让verifyNoMoreInteractions()检测到UserManager.createInstance()中的调用,你需要改用**doReturn()的存根语法**,避免存根时触发真实的Mock方法调用:
private void initializeTest() { doReturn(source).when(dataNetworkPlugin).getElement(anyString()); doReturn(null).when(source).asDataSource(); userManager = UserManager.createInstance(dataNetworkPlugin); }
修改后,存根阶段不会触发Mock方法的实际调用,只有UserManager.createInstance()里的调用会被记录为未验证的调用,此时verifyNoMoreInteractions()就会按预期失败,直到你添加对应的verify()语句。
另外,更新2中测试通过的原因是:你显式验证的调用,和存根+初始化阶段的调用完全对应,没有额外未验证的调用,所以verifyNoMoreInteractions()不会抛出错误。
内容的提问来源于stack exchange,提问作者Gregor Lang

