震惊,原来是这样使⽤Junit5单元测试(Mock测试)
⽬录
Junit5测试
前⾔
众所周知,单元测试对于整个开发流程⽽⾔是⼗分重要的,不过也是⼤家最容易忽略的。多数情况下我们是调⽤Web接⼝,在页⾯上点⼀点项⽬跑⼀跑如果没啥问题就万事⼤吉了。在项⽬的test⽂件夹下空空如也,这⾥就埋下了坑,因为单元测试是对⼀个接⼝的完整测试,接⼝的请求数据啊,格式啊,可能出现的异常啊。写好单元测试也是对整个项⽬完整的⼀个逻辑梳理。下⾯就简单⽤Junit5进⾏总结。
⽂章⼤致从这些⽅⾯⼊⼿,Junit5的常见使⽤,最后再讲讲Mock测试。
相关配置
在springBoot框架下使⽤,pom相关依赖如下。
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
<exclusions>
<exclusion>
<artifactId>junit</artifactId>
<groupId>junit</groupId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>org.junit.jupiter</groupId>
<artifactId>junit-jupiter</artifactId>
<version>5.6.0</version>spring到底是干啥的
<scope>test</scope>
</dependency>
具体的版本号如下:
然后IDEA都有⽣成测试⽤例的快捷键,不需要⾃⼰⼿动创建,快捷键:CTRL+SHRIFT+T。如下图所⽰,选择要测试的⽅法即可。
或者,插⼊快捷键:ALT+Insert,选择test也是同样的效果。
⾃动⽣成的代码还不能跑,还要加点东西上去,需要读取项⽬配置啥的。这⾥也看出Junit5和Junit4还是有很多不⼀样的地⽅,这⾥就不展开了。
/**
* test for bd mapper
*
* @author hxd
* @date 2021/5/31  17:48
*/
@Slf4j
@DisplayName("bd service 测试")
@ExtendWith(SpringExtension.class)
// 这⾥的Application 是项⽬启动类
@SpringBootTest(classes = Application.class, webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)
class IMsgMetricsServiceTest {
@Autowired
private MsgTestMapper mapper;
@DisplayName("存⼊DB测试")
@Test
void save(){
Assertions.assertTrue(true);
}
}
基本的使⽤
其实上⾯的测试⽤例基本能够完成基本的要求了,需要测试的接⼝⾃动注⼊进去,然后测试⽅法。然后这篇⽂章就到这结束了,有这么简单就好了,哈哈,下⾯继续。
断⾔的使⽤
我们⼤多数测试⽤例都不习惯使⽤断⾔,其实代码扫描插件都会提⽰:
这⾥为什么会提⽰要在单元测试中添加断⾔呢?是因为单元测试最后都有⼀个明确的结果,接⼝返回的是什么数据,返回是否为True,返回List是否不为空等。所以断⾔是单元测试最终想得到结果的判断,是⼗分重要的,下⾯举⼏个例⼦。
// 返回list不为空
Assertions.assertFalse(list.isEmpty());
// 返回结果是否为10
Assertions.assertEquals(10, effNum);
// 返回布尔为false
boolean flag = redisUtil.dbSaveLock();
log.info("再次上锁,结果:{}", flag ?"成功":"失败");
Assertions.assertFalse(flag);
// 不过有些测试⽤例没有最终的结果,如果有强迫症喜欢代码⼲⼲净净的话,可以这么写
Assertions.assertTrue(true);
重复测试
有些⽅法需要重复调⽤多次,这⾥可以⽤ @RepeatedTest 具体参考⼤佬的博客:
参数化测试
有时候我们需要测试多个⼊参,但是实际上只有⼏个参数不同,我们就会Copy下,然后改变下参数。实际上我们可以使⽤参数化测试。(这⾥代码扫描也会提⽰重复代码的)
@DisplayName("测试重复测试")
// 参数化测试注解,{0},{1} 占位符代表参数
@ParameterizedTest(name ="渠道:{0},⽬标:{1}")
// 数据源
@CsvSource({
"10001, XXX",
"10004, XXX",
"10003, XXX",
"10002, huawei",
"10002, xiaomi",
"10002, vivo"
})
/
/ ⼊参在这⾥定义
void handleFlowNeedCache(String chCode, String targetType){
SimpleMsgDTO msg =getMsgFlow(chCode, targetType);
handleService.handleFlow(msg);
Assertions.assertTrue(true);
}
这⾥的⽤例只有两个参数,如果参数列表有很多,这⾥也可以使⽤ @AggregateWith 直接转化为对应实体类,我也没写出来,具体参考⼤佬的⽂章:
这⾥我们得想⼀想,存在这种参数很多的情况吗,⼤多数只有会⼏个参数不⼀样的把,个⼈觉得可以把共同的抽出来,不同的参数set进去就⾏了。
并发测试
有时候对于某个接⼝,我们需要并发调⽤,然后查看在⾼并发的执⾏情况。我查了很多博客,⼤多数
写的是加⼊测试junit5测试⽂件,然后使⽤注解 @Execution 。这⾥有个坑,需要注意junit的版本号,不只是 junit-jupiter的版本号,还有junit-jupiter-api的版本号。因为⽀持并发测试需要两个版本号在5.6.X以上,⽽且前⾯提及的两个版本也需要对应,不然不⽣效。参考博客:
我参考博客写了下,不过没有⽣效。我也不想加个配置⽂件就为了测试某个接⼝的并发效果,然后这⾥提供⼀个折中的⽅法,⽤线程池来搞。
重点在提⼀下,要⼿动sleep线程久⼀些,不然没等线程池执⾏完任务主线程会结束了。
@SneakyThrows
@DisplayName("并发测试定时任务")
@Test
void multiTestScheduleTask(){
ThreadPoolExecutor executor =(ThreadPoolExecutor) wFixedThreadPool(2);
// 这⾥是重点,要sleep久⼀些,不然没等线程池执⾏完任务主线程会等结束了
TimeUnit.SECONDS.sleep(10);
Assertions.assertTrue(true);
}
还有另⼀种利⽤Java的并发包进⾏并发测试。
@SneakyThrows
@Test
void test(){
CountDownLatch cdl =new CountDownLatch(2);
Thread t1 =new Thread(()->{
try{
scheduleTask.task();
}finally{
}
});
t1.setName("thread-1");
Thread t2 =new Thread(()->{
try{
scheduleTask.task();
}finally{
}
});
t2.setName("thread-2");
t1.start();
t2.start();
cdl.await();
}
Mock测试
前⾔
Mock测试是啥呢,具体百度看看。我所理解的是,单元测试所测试的接⼝都会依赖于其他的Service,
这些Service返回的结果不⼀样都是正确的,例如Redis集挂了,使⽤RedisTemplate肯定会报错,⼜或者DB挂了,Mapper也是会报错的,那边依赖这些的Servcie就会报错,但是逻辑上单元测试⽤例是正常的。那么Mock的意义就是使某个依赖的Bean调⽤某个⽅法⽆论什么情况下都是返回⼀个期望值。
基本使⽤
前提
这⾥就要提到Spring的三种注⼊⽅式了,这⾥不展开,具体参考:
这⾥推荐⼤家使⽤setter注⼊的⽅式,为什么呢?下⾯就能看出好处。如下代码:
private RedisUtil redisUtil;
@Autowired
public void setRedisUtil(RedisUtil redisUtil){
}
使⽤

版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。