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,具体配置如下:

# 异步线程配置
# 核心线程数
async.executor.thread.core_pool_size=5
# 最大线程数
async.executor.thread.max_pool_size=8
# 任务队列大小
async.executor.thread.queue_capacity=2
# 线程池中线程的名称前缀
async.executor.thread.name.prefix=async-service-
# 缓冲队列中线程的空闲时间
async.executor.thread.keep_alive_seconds=100

2.测试代码
1.ThreadPoolTaskExecutor 配置类

@Configuration
/* @PropertySource是找的target目录下classes目录下的文件,
*resources目录下的文件编译后会生成在classes目录
*/
@PropertySource(value = {"classpath:executor.properties"}, ignoreResourceNotFound=false, encoding="UTF-8")
@Slf4j
public class ExecutorConfig {

    @Value("${async.executor.thread.core_pool_size}")
    private int corePoolSize;
    @Value("${async.executor.thread.max_pool_size}")
    private int maxPoolSize;
    @Value("${async.executor.thread.queue_capacity}")
    private int queueCapacity;
    @Value("${async.executor.thread.name.prefix}")
    private String namePrefix;
    @Value("${async.executor.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.execute(new ThreadTest());
        }
        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
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: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-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
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
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
main1:2
main1:3
main1:4
main1:5
main1:6
main1:7
main1:8
main1:9
main1:0
main1:1
main1:2
main1:3
main1:4
main1:5
main1:6
main1:7
main1:8
main1:9
main1:0
main1:1
main1:2
main1:3
main1:4
main1:5
main1:6
main1:7
main1:8
main1:9
2021-04-05 18:29:16.636  INFO 10364 --- [           main] o.s.s.concurrent.ThreadPoolTaskExecutor  : Shutting down ExecutorService 'taskExecutor'
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-733:0
async-service-733:1
async-service-733:2
async-service-733:3
async-service-733:4
async-service-733:5
async-service-733:6
async-service-733:7
async-service-733:8
async-service-733:9
async-service-322:0
async-service-322:1
async-service-322:2
async-service-322:3
async-service-322:4
async-service-322:5
async-service-322:6
async-service-322:7
async-service-322:8
async-service-322:9
async-service-424:4
async-service-424:5
async-service-424:6
async-service-630:2
async-service-630:3
async-service-630:4
async-service-630:5
async-service-630:6
async-service-630:7
async-service-630:8
async-service-630:9
async-service-424:7
async-service-424:8
async-service-424:9
2021-04-05 18:29:16.662  INFO 10364 --- [extShutdownHook] o.s.s.concurrent.ThreadPoolTaskExecutor  : Shutting down ExecutorService 'taskExecutor'

结果分析:
(1)通常 ThreadPoolTaskExecutor 是和 @Async 一起使用。在一个方法上添加 @Async 注解,表明是异步调用方法函数。@Async 后面加上线程池的方法名或 bean 名称,表明异步线程会加载线程池的配置。

(2).一定要在启动类上添加 @EnableAsync 注解,这样 @Async 注解才会生效。

  • 1
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

叶枫^_^

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值