大家好! 在我们之前的博客关于thenReturn和thenAnswer模拟方法之间的区别之后 ,我们又回来了关于Mockito的另一个有趣的博客。 在这里,我们将讨论“如何用Mockito模拟无效方法”。 让我们开始吧!
在编写代码时,总是至少有一种方法返回“ void”,并且在某个时间点需要模拟“ void”方法。 那么我们如何去做呢? 让我们在下面的博客中使用Mockito一起解决这个问题。
Mockito是用于编写单元测试的最著名的模拟框架之一。 如果您不喜欢模拟,可以在模拟网站上了解更多。
为什么我们需要模拟void方法?
假设我们有一个方法。 在此方法中,我们称为另一个void方法。 现在,当您要为该方法编写测试用例时,我们如何测试void方法被调用? 另外,是否将正确的参数传递给void方法?
在这种情况下,mockito可以帮助我们。
让我们举个例子,我们有一个UserService类。 在此类中,我们有一个updateName()方法。
public UserService{ ... public void updateName(Long id, String name){ userRepository.updateName(id, name); } }
现在,我们要为UserService类编写单元测试并模拟userRepository。
但是,在此测试用例中,我们唯一需要验证的是使用正确的参数集调用了userRepository中的updateName()方法。
为此,我们需要模拟updateName()方法,捕获参数并验证参数。
这里要注意的最重要的一点之一是,我们不能仅仅使用Mockito的when-then机制来模拟void方法。 因为,mockito的when()方法适用于返回值,而方法无效时则不适用。
如何在Mockito中模拟void方法?
在Mockito中,我们可以使用不同的方法来调用实数方法或模拟void方法。 我们可以根据要求使用其中一个选项
- doNothing() :完全忽略对void方法的调用,这是默认行为
- doAnswer() :在调用void方法时执行一些运行时或复杂的操作
- doThrow() : 调用模拟的 void方法时引发异常
- doCallRealMethod() :不要模拟并调用真实方法
1)使用doNothing()
如果我们只想完全忽略void方法调用,则可以使用doNothing()。
在模拟中,对于模拟对象的每种方法,doNothing是默认行为。 因此,如果您不想验证参数,则使用doNothing是完全可选的。 在所有代码执行类似的行为之后,
将doNothing()用于void方法的示例
@Test public void testUpdateNameWithDoNothingVerifyRepositoryCall() { doNothing().when(mockedUserRepository).updateName(anyLong(),anyString()); userService.updateName(1L, "void mock test" ); verify(mockedUserRepository, times(1)).updateName(1L, "void mock test" ); }
不对空方法使用doNothing()
@Test public void testUpdateNameWithOutDoNothingVerifyRepositoryCall() { userService.updateName(1L, "void mock test" ); verify(mockedUserRepository, times(1)).updateName(1L, "void mock test" ); }
使用doNothing()进行参数捕获的示例
我们可以使用参数捕获来做不同的事情。 在这里,我们将只验证捕获的值
@Test public void testUpdateNameUsingArgumentCaptor() { ArgumentCaptor<Long> idCapture = ArgumentCaptor.forClass(Long. class ); ArgumentCaptor<String> nameCapture = ArgumentCaptor.forClass(String. class ); doNothing().when(mockedUserRepository).updateName(idCapture.capture(),nameCapture.capture()); userService.updateName(1L, "void mock test" ); assertEquals(1L, idCapture.getValue()); assertEquals( "void mock test" , nameCapture.getValue()); }
2)将doAnswer()用于void方法
如果我们不想调用真实方法,则需要执行一些运行时操作,请使用doAnswer。
让我们以doAnswer为例,使用doAnswer打印并验证参数
@Test public void testUpdateNameUsingDoAnswer() { doAnswer(invocation -> { long id = invocation.getArgument(0); String name = invocation.getArgument(1); System.out.println( "called for id: " +id+ " and name: " +name); assertEquals(1L, id); assertEquals( "void mock test" , name); return null; }).when(mockedUserRepository).updateName(anyLong(),anyString()); userService.updateName(1L, "void mock test" ); verify(mockedUserRepository, times(1)).updateName(1L, "void mock test" ); }
3)使用doThrow()引发异常
如果要在调用方法时引发异常,则可以使用嘲笑的doThrow()方法。
让我们举一个例子,当使用null id调用updateName()方法时,我们将引发InvalidParamException。
@Test(expected = InvalidParamException. class ) public void testUpdateNameThrowExceptionWhenIdNull() { doThrow( new InvalidParamException()) .when(mockedUserRepository).updateName(null,anyString(); userService.updateName(null, "void mock test" ); }
4)使用doCallRealMethod()进行真实方法调用
有时有必要从模拟对象中调用真实方法,在这种情况下,我们需要使用doCallRealMethod(),因为doNothig()是默认行为。
在以下示例中,即使是模拟对象,也会调用userRepository中的真实方法。
@Test public void testUpdateNameCallRealRepositoryMethod() { doCallRealMethod().when(mockedUserRepository).updateName(anyLong(), anyString()); userService.updateName(1L, "calling real method" ); verify(mockedUserRepository, times(1)).add(1L, "calling real method" ); }
快速阅读
- 无效方法通常被模拟以检查是否使用正确的参数调用
- 对于嘲笑void方法,当嘲笑机制无法工作时,因为它需要返回值
- 可以使用doNothing(),doAnswer(),doThrow()或doCallRealMethod()处理无效方法
- doNothing() :完全忽略void方法
- doAnswer() :执行一些运行时或复杂的操作
- doThrow() : 调用模拟的 void方法时引发异常
- doCallRealMethod() :不要模拟并调用真实方法
- 对于模拟对象,noNothing是每种方法的默认行为
翻译自: https://www.javacodegeeks.com/2020/06/mock-void-method-with-mockito.html