SpringBoot如何使⽤注解开启测试功能
在实际开发中,经常会⽤到单元,切⽚,功能的测试。我们的项⽬中常⽤的测试功能的框架是Spring Test与JUnit测试框架结合起来的。其提供了便捷⾼效的测试⼿段。⽽Spring Boot Test 是在Spring Test之上的再次封装,增加了切⽚测试,增强了mock能⼒。
单元测试:⼀般⾯向某⼀个简单的⽅法,在对应测试的⽅法上加上注解@Test,编写⼀般业务代码时,测试成本较⼤。
切⽚测试:⼀般⾯向某⼀个⼩的功能模块,在对应测试的类上加上注解@RunWith @WebMvcTest @SpringBootTes等,⽤于测试某⼀项边界功能,介于单元测试和功能测试之间。涉及到的注解有。
功能测试:⼀般⾯向某个由多个⼩的功能模块组成的完整的业务功能,在对应测试的类上加上注解@RunWith @SpringBootTest等,同时也可以使⽤切⾯测试中的mock能⼒。
总结:实际上⽆论是单元测试,还是切⽚测试,功能测试都是实现某⼀项功能的测试,区别不⼤,只要在对应的类上加上两个功能测试模块的⼤注解@RunWith @SpringBootTest再配合其他的⼩注解即可完成所有功能模块的测试。
@SpringBootTest注解的作⽤:
@SpringBootTest替代了spring-test中的@ContextConfiguration注解,⽬的是加载ApplicationContext,启动spring容器。使⽤
@SpringBootTest时并没有像@ContextConfiguration⼀样显⽰指定locations或classes属性,原因在于@SpringBootTest注解会⾃动检索程序的配置⽂件,检索顺序是从当前包开始,逐级向上查被@SpringBootApplication或@SpringBootConfiguration注解的类
@RunWith注解的作⽤:
@RunWith作⽤就是⼀个运⾏器,其常⽤的⽤法如下:
@RunWith(JUnit4.class) 就是指⽤JUnit4来运⾏
@RunWith(SpringJUnit4ClassRunner.class),让测试运⾏于Spring测试环境
@RunWith(Suite.class) 的话就是⼀套测试集合,
@ContextConfiguration Spring整合JUnit4测试时,使⽤注解引⼊多个配置⽂件
JUnit4和JUnit5的区别:
我们前⾯讲到项⽬中常⽤的测试功能的框架是Spring Test与JUnit测试框架结合起来的,但是JUnit常⽤的版本需要注意区分⼀下,较早的JUnit3就不赘述了,Java测试默认依赖版本是JUnit4的4.12,但是JUnit5和JUnit4差别⽐较⼤,集成⽅式上存在不同。@RunWith是Junit4提供的注解,将Spring和Junit链接了起来。假如使⽤Junit5,不再需要使⽤@ExtendWith注解,@SpringBootTest和其它@对应的后缀名为Test的注解默认已经包含了该注解
前⾯讲了⼀些理论的知识,还是需要实际⽤⼀个demo来展⽰完整的测试功能是如何进⾏的。以便读者参考完成⾃⼰的测试需要。
测试的功能需求:
针对多线程⼯具类ThreadPoolTaskExecutor,以⾃定义的创建线程的⽅式(三种创建多线程⽅式之⼀)去创建⼀个线程加⼊到由线程⼯具类ThreadPoolTaskExecutor管理的线程池中去。
1.添加依赖和配置⽂件:
(1).依赖的添加
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-test</artifactId>
</dependency>
注:读者在想为啥没有版本,因为我z这个依赖是交由⽗版本进⾏依赖管理(当然读者也可以⾃⾏指定对应的依赖版本)。⽗版本依赖的配置如下:
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.2.2.RELEASE</version>
</parent>
<!--需要在build下配置maven plugin,使⽤plugin⼯具进⾏版本依赖管理--> <build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
当然也可以直接指定版本依赖,如下所⽰:
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-test</artifactId>
<version>5.2.7.RELEASE</version>
</dependency>
(2)配置环境,配置⽂件名executor.properties,具体配置如下:
# 异步线程配置
# 核⼼线程数
<_pool_size=5
# 最⼤线程数
# 任务队列⼤⼩
# 线程池中线程的名称前缀
# 缓冲队列中线程的空闲时间
2.测试代码:
1.ThreadPoolTaskExecutor 配置类
@Configuration
/* @PropertySource是的target⽬录下classes⽬录下的⽂件,
*resources⽬录下的⽂件编译后会⽣成在classes⽬录
*/
@PropertySource(value ={"classpath:executor.properties"}, ignoreResourceNotFound=false, encoding="UTF-8") @Slf4j
public class ExecutorConfig {
@Value("${_pool_size}")
private int corePoolSize;
@Value("${utor.thread.max_pool_size}")
private int maxPoolSize;
@Value("${utor.thread.queue_capacity}")
private int queueCapacity;
@Value("${utor.thread.name.prefix}")
private String namePrefix;
@Value("${utor.thread.keep_alive_seconds}")
private int keepAliveSeconds;
@Bean(name ="taskExecutor")
public ThreadPoolTaskExecutor taskExecutor(){
log.info("启动");
ThreadPoolTaskExecutor executor =new ThreadPoolTaskExecutor();
// 核⼼线程数
executor.setCorePoolSize(corePoolSize);
// 最⼤线程数
executor.setMaxPoolSize(maxPoolSize);
// 任务队列⼤⼩
executor.setQueueCapacity(queueCapacity);
// 线程前缀名
executor.setThreadNamePrefix(namePrefix);
// 线程的空闲时间
executor.setKeepAliveSeconds(keepAliveSeconds);
/
/ 拒绝策略
executor.setRejectedExecutionHandler(new ThreadPoolExecutor.CallerRunsPolicy());
// 线程初始化
executor.initialize();
return executor;
}
}
2.⾃定义的线程:
public class ThreadTest implements Runnable{
public ThreadTest(){
}
@Override
public void run(){
System.out.println("测试");
}
}
3.测试demo(测试模块):
其中@RunWith和@SpringBootTest必须存在,其他配置类型的注解可以在需要时添加。
/*Spring使⽤ThreadPoolTaskExecutor⾃定义线程池及实现异步调⽤*/
/*@SpringBootTest作⽤是启动Spring的ApplicationContext,⼀般情况下,*使⽤@SpringBootTest后,Spring将加载所有被管理的bean,
*基本等同于启动了整个服务,此时便可以开始功能测试。
*/
@SpringBootTest
/*@RunWith(SpringRunner.class)是JUnit的注解,
*作⽤是关联Spring Boot Test,使运⾏JUnit时同时启动Spring
*/
@RunWith(SpringRunner.class)
public class MultiThreadTest {
@Autowired
private ThreadPoolTaskExecutor taskExecutor;
@Test
@Async
public void test(){
int n =20;
for(int i =0; i < n; i++){//executor
}
taskExecutor.destroy();
}
}
控制台输出结果:
async-service-118:0
async-service-118:1
async-service-118:2
async-service-118:3
async-service-118:4
async-service-118:5
async-service-118:6
async-service-118:7
async-service-118:8
async-service-118:9
springboot框架的作用async-service-220:0
async-service-220:1
async-service-220:2
async-service-220:3
async-service-220:4
async-service-220:5
async-service-220:6
async-service-220:7
async-service-220:8
async-service-220:9
async-service-424:0
async-service-424:1
async-service-424:2
async-service-424:3
async-service-424:4
async-service-424:5
async-service-424:6
async-service-424:7
async-service-424:8
async-service-424:9
async-service-526:0
async-service-526:1
async-service-526:2
async-service-526:3
async-service-526:8 async-service-526:9 async-service-526:0 async-service-526:1 async-service-526:2 async-service-526:3 async-service-526:4 async-service-526:5 async-service-526:6 async-service-526:7 async-service-526:8 async-service-526:9 async-service-526:0 async-service-526:1 as
ync-service-526:2 async-service-526:3 async-service-526:4 async-service-526:5 async-service-526:6 async-service-526:7 async-service-526:8 async-service-526:9 async-service-526:0 async-service-526:1 async-service-526:2 async-service-526:3 async-service-526:4 async-service-526:5 async-service-526:6 async-service-526:7 async-service-526:8 async-service-526:9 async-service-118:0 async-service-118:1 async-service-118:2 async-service-118:3 async-service-118:4 async-service-118:5 async-service-118:6 async-service-118:7 async-service-118:8 async-service-118:9 main1:0
main1:1
async-service-424:0 async-service-424:1 async-service-630:0 async-service-630:1 async-service-424:2 async-service-424:3 async-service-839:0 async-service-839:1 async-service-839:2 async-service-839:3 async-service-839:4 async-service-839:5 async-service-839:6 async-service-839:7 async-service-839:8 async-service-839:9 async-service-526:0
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。
发表评论