Mockito框架Mock Void方法

在编写代码时,总是有方法返回void,并且在某个测试用例需要模拟void方法。那么我们如何去做呢?让我们一起在下面的内容中使用Mockito完成这个需求。

  • Mockito是用于编写单元测试的最著名的模拟框架之一。

为什么模拟void方法

假设我们有一个方法A,在此方法中,使用了另一个void方法B。现在,当要为该方法编写测试用例时,我们如何测试B方法被调用?另外,是否将正确的参数传递给B方法?在这种情况下,Mockito可以帮助我们解决这个问题。

让我们举个例子,我们有一个UserService类。在此类中,我们有一个updateName()方法。

public UserService{

   public void updateName(Long id, String name){
      userRepository.updateName(id, name);
   }
}

现在,我们要为UserService类编写单元测试并模拟userRepository。但是,在此测试用例中,我们唯一需要验证的是使用正确的参数集调用了userRepository中的updateName()方法。为此,我们需要模拟updateName()方法,捕获参数并验证参数。

这里要注意的最重要的是,我们不能仅仅使用Mockitowhen-then机制来模拟void方法。因为,Mockitowhen()方法适用于返回值,而方法返回值是void时则不适用。

如何在Mockito中模拟void方法

Mockito中,我们可以使用不同的方法来调用实例方法或模拟void方法。根据要求使用其中一个选项:

  • doNothing():完全忽略对void方法的调用,这是默认
  • doAnswer():在调用void方法时执行一些运行时或复杂的操作
  • doThrow():调用模拟的 void方法时引发异常
  • doCallRealMethod():不要模拟并调用真实方法

使用doNothing()

如果我们只想完全忽略void方法调用,则可以使用doNothing()

在测试用例中,对于模拟对象的每种方法,doNothing是默认行为。因此,如果不想验证参数,则使用doNothing是完全可以的。

doNothing()用于void方法的Demo

@Test
public void test001() {
   doNothing().when(mockedUserRepository).updateName(anyLong(),anyString());
 
   userService.updateName(1L,"FunTester");
     
   verify(mockedUserRepository, times(1)).updateName(1L,"FunTester");
}

不对空方法使用doNothing()

@Test
public void test002() {
 
   userService.updateName(1L,"FunTester");
     
   verify(mockedUserRepository, times(1)).updateName(1L,"FunTester");
}

使用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,"FunTester");
     
   assertEquals(1L, idCapture.getValue());
   
   assertEquals("FunTester", nameCapture.getValue());
}

将doAnswer()用于void方法

如果我们不想调用真实方法,则需要执行一些运行时操作,请使用doAnswer()

下面是使用doAnswer()打印并验证参数的Demo:

@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("FunTester", name);
 
      return null;
}).when(mockedUserRepository).updateName(anyLong(),anyString());
 
   userService.updateName(1L,"FunTester");
   verify(mockedUserRepository, times(1)).updateName(1L,"FunTester");
}

使用doThrow()引发异常

如果要在调用方法时引发异常,则可以使用嘲笑的doThrow()方法。

让我们举一个例子:当使用null作为id调用updateName()方法时,我们将引发InvalidParamException

@Test(expected = InvalidParamException.class)
public void testUpdateNameThrowExceptionWhenIdNull() {
   doThrow(new InvalidParamException())
      .when(mockedUserRepository).updateName(null,anyString();
   userService.updateName(null,"FunTester");
}

使用doCallRealMethod()进行真实方法调用

有时有必要从模拟对象中调用真实方法,在这种情况下,我们需要使用doCallRealMethod(),因为doNothig()是默认行为。

在以下示例中,即使是模拟对象,也会调用userRepository中的真实方法。

@Test
public void testUpdateNameCallRealRepositoryMethod() {
 
   doCallRealMethod().when(mockedUserRepository).updateName(anyLong(), anyString());
  
   userService.updateName(1L,"真实调用方法");
  
   verify(mockedUserRepository, times(1)).add(1L,"真实调用方法");
}

  • 公众号FunTester首发,更多原创文章:FunTester430+原创文章,欢迎关注、交流,禁止第三方擅自转载。

热文精选

posted @ 2020-08-06 15:24  FunTester  阅读(4479)  评论(0编辑  收藏  举报