项目的结尾都要进行代码覆盖率的编写,其中有一些小经验分享一下。
主要设计 静态方法的模拟,正常场景的模拟 异常场景的模拟。 下面这个例子小白看了能解决很多问题
引入的依赖在最后
package com.cn.joey;
import com.cn.joey.light.entity.WorkerNode;
import com.cn.joey.light.mapper.WorkerNodeMapper;
import com.cn.joey.light.service.LoginService;
import com.cn.joey.light.utils.TimeUtil;
import lombok.extern.slf4j.Slf4j;
import org.junit.Assert;
import org.junit.Before;
import org.junit.Test;
import org.mockito.*;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.core.ValueOperations;
import java.io.UnsupportedEncodingException;
import java.util.Date;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.Mockito.*;
@Slf4j
class SwordApplicationTests {
@InjectMocks
LoginService loginServiceTest;
@Mock
WorkerNodeMapper workerNodeMapper;
@Mock
RedisTemplate redisTemplate;
@Before
public void setup() throws UnsupportedEncodingException{
loginServiceTest = spy(new LoginService());//这个很重要
MockitoAnnotations.initMocks(this);//开启mock 并且注入相应资源 有的是openMocks;本次是initMocks
}
/**
* LoginService中的具体实现方法
*/
@Test
public void saveLoginMsgTest01(){
MockedStatic<TimeUtil> time = Mockito.mockStatic(TimeUtil.class);//如果你使用涉及到静态方法的类必须这样写
try{
WorkerNode record = new WorkerNode();
record.setId(1l);
record.setCreated(new Date());
//逻辑 如果用任何参数查询,那么会返回查询结果。 模拟查询类
when(workerNodeMapper.selectByPrimaryKey(any())).thenReturn(record);
// time.formatDate(record.getCreated(),"yyyy-MM-dd HH:mm:ss");//模拟静态方法
String isNotNull = loginServiceTest.saveLoginMsg();//**调用的具体方法,上面都是方法中具体逻辑的模拟数据
Assert.assertNotNull(isNotNull);//数据不为空
}catch (Exception e){
e.printStackTrace();
}finally {
time.close();//释放静态全局资源,不然会报错
}
}
/**
* 异常情况模拟
*/
@Test
public void saveLoginMsgTest02(){
MockedStatic<TimeUtil> time = Mockito.mockStatic(TimeUtil.class);//如果你使用涉及到静态方法的类必须这样写
try{
WorkerNode record = new WorkerNode();
record.setId(1l);
record.setCreated(new Date());
//这条逻辑异常情况的模拟
try {
Mockito.doAnswer(invocation->{throw new Exception();}).when(workerNodeMapper).selectByPrimaryKey(any());
} catch (Exception e) {
throw new RuntimeException(e);
}
// time.formatDate(record.getCreated(),"yyyy-MM-dd HH:mm:ss");//模拟静态方法
//方法的触发调用,上面的都是方法中场景需要的数据
String isNotNull = loginServiceTest.saveLoginMsg();//***调用的具体方法,上面都是方法中具体逻辑的模拟数据
Assert.assertNotNull(isNotNull);//数据不为空
}catch (Exception e){
e.printStackTrace();
}finally {
time.close();//释放静态全局资源,不然会报错
}
}
/**
* 如何mock redis中的opsForValue
*/
@Test
public void mockRedisTest01(){
//首先mock RedisTemplate
RedisTemplate<String,String> mockRedisTemplate = Mockito.mock(RedisTemplate.class);
//其次mock RedisTemplate 中具体方法的返回对象 这里以edisTemplate.opsForValue()函数返回对象为例子
ValueOperations<String,String> redisMockValue = Mockito.mock(ValueOperations.class);
redisMockValue.set("a","1");//设置mock值
Mockito.when(redisTemplate.opsForValue()).thenReturn(redisMockValue);
//**关键一步,将上面@Mock注入的redisTemplate 强行负值为我们自己mock的mockRedisTemplate
redisTemplate=mockRedisTemplate;
//获取mock数值
Mockito.when(redisMockValue.get(any())).thenReturn("redisMockValue");
}
}
mockito的依赖
<dependency>
<groupId>org.mockito</groupId>
<artifactId>mockito-core</artifactId>
<version>3.6.28</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.mockito</groupId>
<artifactId>mockito-inline</artifactId>
<version>3.6.28</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.mockito</groupId>
<artifactId>mockito-junit-jupiter</artifactId>
<version>3.4.0</version>
<scope>test</scope>
</dependency>