用好 mock 事半功倍
一、常用的mock工具
在Java开发中,Mock工具可用于单元测试和模拟对象的创建
1、Mockito:
????????Mockito是Java中最受欢迎的Mocking框架之一。
????????提供简单易用的API,可以方便地创建和配置模拟对象。
????????支持验证模拟对象的行为和交互。
????????提供了注解支持,用于简化测试代码的编写。
????????文档丰富,社区活跃,广泛应用于Java项目中,SpringBootTest 默认使用的也是 Mockito
2、EasyMock:????????EasyMock是另一个常用的Java Mocking框架。
????????提供了单的API来创建和配置模拟对象。
????????支持验证模拟对象的行为和交互。
????????使用了基于录制和回放的模拟对象创建方式。
????????语法相对于Mockito来说稍微繁琐一些。
????????文档相对较少,但社区比较活跃。
3、PowerMock:????????PowerMock是一个扩展了Mockito和EasyMock功能的工具。
????????可以模拟静态方法、构造函数、私有方法等。
????????PowerMock的使用相对复杂,需要在测试类上使用特定的注解。
????????在处理一些特殊场景(如遗留代码)时非常有用。
????????文档相对较少,但在特定情况下仍然是一个有价值的工具。
二、spring / 非 spring 场景测试验证
选取的mock工具为 mockito?,其中依赖版本为?mockito-core:3.3.3?
<dependency> <groupId>org.mockito</groupId> <artifactId>mockito-core</artifactId> <version>3.3.3</version> <scope>test</scope> </dependency>
1、场景假设,我们的希望实现用户在线时长查询的方法,其中需要校验用户是否登陆(第三方接口)
@Service
public class LoginService {
@Resource
private SSOService ssoService;
/**
* 调用单点登陆系统判断
* @param userId
* @return
*/
public boolean isLogin(String userId) {
UserInfo userInfo = ssoService.getLoginInfo(userId);
if (Objects.nonNull(userInfo)) {
return true;
}
return false;
}
}
@Service
public class UserService {
@Resource
private LoginService loginService;
/**
* 获取用户在线时常
* @return
*/
public Integer getUserOnlineTimes(String userId){
//判断是否登陆
if(!loginService.isLogin(userId)){
return 0;
}
return (int)(Math.random() * 100) + 1;
}
}
2、在没有SSO调用授权之前我们不好进行单元测试,这时就需要用的mock工具了
a、非 spring 方式使用mock进行测试验证,通过反射注入 mock 类
@Slf4j
@RunWith(MockitoJUnitRunner.class)
public class UserServiceTest {
@Mock
private LoginService loginServiceMock;
@Test
public void getUserOnlineTimes() throws NoSuchFieldException, IllegalAccessException {
// 设置 mock 场景
Mockito.when(loginServiceMock.isLogin("zhangsan")).thenReturn(false);
Mockito.when(loginServiceMock.isLogin("lisi")).thenReturn(true);
// 反射赋值属性 或 在 userService 作为成员变量,使用 @InjectMocks 注入
UserService userService = new UserService();
Field loginService = userService.getClass().getDeclaredField("loginService");
loginService.setAccessible(true);
loginService.set(userService, loginServiceMock);
//验证
Integer onlineTimes = userService.getUserOnlineTimes("zhangsan");
Assert.assertEquals(Integer.valueOf(0), onlineTimes);
onlineTimes = userService.getUserOnlineTimes("lisi");
Assert.assertTrue(onlineTimes > 0);
}
}
b、非 spring 方式使用mock进行测试验证,通过 mockito 注解 @InjectMocks 注入
@Slf4j
@RunWith(MockitoJUnitRunner.class)
public class UserServiceTest2 {
@Mock
private LoginService loginServiceMock;
@InjectMocks
private UserService userService;
@Test
public void getUserOnlineTimes() {
// 设置 mock 场景
Mockito.when(loginServiceMock.isLogin("zhangsan")).thenReturn(false);
Mockito.when(loginServiceMock.isLogin("lisi")).thenReturn(true);
//验证
Integer onlineTimes = userService.getUserOnlineTimes("zhangsan");
Assert.assertEquals(Integer.valueOf(0), onlineTimes);
onlineTimes = userService.getUserOnlineTimes("lisi");
Assert.assertTrue(onlineTimes > 0);
// 验证mock方法被执行的次数
Mockito.verify(loginServiceMock, Mockito.times(1)).isLogin("zhangsan");
}
}
c、spring 容器中使用mock进行测试验证
@Slf4j
@SpringBootTest
@RunWith(SpringRunner.class)
public class UserServiceTestInSpring {
@MockBean
private LoginService loginServiceMock;
@Resource
private UserService userService;
@Before
public void init(){
// 启用mock
MockitoAnnotations.initMocks(this);
}
@Test
public void getUserOnlineTimes() {
// 设置 mock 场景
Mockito.when(loginServiceMock.isLogin("zhangsan")).thenReturn(false);
Mockito.when(loginServiceMock.isLogin("lisi")).thenReturn(true);
//验证
Integer onlineTimes = userService.getUserOnlineTimes("zhangsan");
Assert.assertEquals(Integer.valueOf(0), onlineTimes);
onlineTimes = userService.getUserOnlineTimes("lisi");
Assert.assertTrue(onlineTimes > 0);
}
}
三、mockito 使用总结
Mockito提供了强大的验证功能,支持验证模拟对象的方法调用次数、参数和顺序,以确保代码的预期行为,另外注解的支持可以轻松地创建和注入模拟对象,让测试代码更加简化,但是Mockito本身无法直接模拟静态方法和私有方法。对于这些场景,可以使用 PowerMock 或者使用java代码直接构造生成
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。 如若内容造成侵权/违法违规/事实不符,请联系我的编程经验分享网邮箱:veading@qq.com进行投诉反馈,一经查实,立即删除!