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()
方法,捕获参数并验证参数。
这里要注意的最重要的是,我们不能仅仅使用Mockito
的when-then机制来模拟void
方法。因为,Mockito
的when()
方法适用于返回值,而方法返回值是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+原创文章,欢迎关注、交流,禁止第三方擅自转载。
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】凌霞软件回馈社区,博客园 & 1Panel & Halo 联合会员上线
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】博客园社区专享云产品让利特惠,阿里云新客6.5折上折
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 浏览器原生「磁吸」效果!Anchor Positioning 锚点定位神器解析
· 没有源码,如何修改代码逻辑?
· 一个奇形怪状的面试题:Bean中的CHM要不要加volatile?
· [.NET]调用本地 Deepseek 模型
· 一个费力不讨好的项目,让我损失了近一半的绩效!
· PowerShell开发游戏 · 打蜜蜂
· 在鹅厂做java开发是什么体验
· 百万级群聊的设计实践
· WPF到Web的无缝过渡:英雄联盟客户端的OpenSilver迁移实战
· 永远不要相信用户的输入:从 SQL 注入攻防看输入验证的重要性