【SpringBoot(四)】还不懂文件上传?JUnit使用?本文带你了解SpringBoot的文件上传、异常处理、组件注入等知识!并且带你领悟JUnit单元测试的使用!

本文涉及的产品
应用实时监控服务-可观测链路OpenTelemetry版,每月50GB免费额度
服务治理 MSE Sentinel/OpenSergo,Agent数量 不受限
云原生网关 MSE Higress,422元/月
简介: Spring专栏第四章,本文带你上手 SpringBoot 的文件上传、异常处理、组件注入等功能并且为你演示Junit5的基础上手体验

1. 文件上传

1.1 页面表单

<form role="form" action="/upload" method="post" enctype="multipart/form-data">
    <div class="form-group">
        <label for="exampleInputEmail1">邮箱</label>
        <input type="email" class="form-control" name="email"  id="exampleInputEmail1" placeholder="Enter email">
    </div>
    <div class="form-group">
        <label for="exampleInputPassword1">名字</label>
        <input type="password" class="form-control" name="username" id="exampleInputPassword1" placeholder="Password">
    </div>
    <div class="form-group">
        <label for="exampleInputFile">壁纸</label>
        <input type="file" id="exampleInputFile" name="wallpaperInputFile">
    </div>
    <div class="form-group">
        <label for="exampleInputFile">批量照片</label>
        <!-- multiple 代表该 file 属性可以支持多文件上传 -->
        <input type="file" name="photos" multiple>
    </div>
    <div class="checkbox">
        <label>
            <input type="checkbox"> Check me out
        </label>
    </div>
    <button type="submit" class="btn btn-primary">提交</button>
</form>

1.2 文件上传代码

@PostMapping(value = "/upload",consumes = MediaType.MULTIPART_FORM_DATA_VALUE)
public String upload(
    @RequestPart("wallpaperInputFile") MultipartFile wallpaperInputFile,
    @RequestPart("photos") MultipartFile[] photos) throws IOException {
    if (!wallpaperInputFile.isEmpty()){
        String originalFilename = wallpaperInputFile.getOriginalFilename();
        wallpaperInputFile.transferTo(new File("F:\\"+originalFilename));
    }
    if ((photos.length > 0)) {
        for (MultipartFile photo : photos) {
            if (!photo.isEmpty()) {
                String originalFilename = photo.getOriginalFilename();
                photo.transferTo(new File("F:\\"+originalFilename));
            }
        }
    }
    return "index";
}

1.3 注意事项

1.3.1 文件上传大小限量

当提示文件大小过大时,可以修改 spring.servlet.max-file-size 和 max-request-file-size 属性来解决这个问题

# -------------- SpringBoot - properties ----------------
# 文件最大大小
spring.servlet.multipart.max-file-size=10MB
# 请求最大大小
spring.servlet.multipart.max-request-size=100MB

1.3.2 content-Type

文件上传需要指定 content-type 值为:multipart/form-data

因此,无论在控制器还是表单都必须设置好对应的类型

/**
* ----------------控制器-----------
*
*  consumes 使用内容类型 = MediaType.MULTIPART_FORM_DATA_VALUE -- "multipart/form-data"
*  MULTIPART_FORM_DATA_VALUE 常量就是 multipart/form-data
*  该属性限定了接收的内容类型
*/
@PostMapping(value = "/upload",consumes = MediaType.MULTIPART_FORM_DATA_VALUE)
<!--
  enctype="multipart/form-data"
  
  enctype 属性可以设置 content-type 的值
  这里直接指定为 multipart/form-data**
-->
<form role="form" action="/upload" method="post" enctype="multipart/form-data"></form>

1.4 文件上传(自动配置)原理

文件上传自动配置类 - MultipartAutoConfiguration-MultiaprtProperties

  • 自动配置好了 StandardServletMultipartResolver【文件上传解析器】
  • 原理步骤:
  1. 请求进来使用文件上传解析器(isMultipart)判断并封装(resolveMultipart返回MultipartHttpServletRequest)文件上传请求
  2. 参数解析器来解析请求中的文件内容,封装成 MultipartFile
  3. 将request中文件信息封装为一个Map

2. 异常处理

2.1 错误处理

2.1.1 默认规则

  • 默认情况下,Spring Boot 提供/error处理所有错误的映射
  • 对于机器客户端,它将生成JSON响应,其中包含错误,HTTP状态和异常消息的详细信息,对于浏览器客户端,响应一个”whiteLabel“错误视图,以HTML格式呈现相同的数据

  • 要对其进行自定义,添加View解析为error
  • 要完全替换默认行为,可以实现ErrorController并注册该类型的Bean定义,或添加ErrorAttributes类型的组件以使用现有机制但替换其内容
  • error/下的4xx,5xx页面会被自动解析

2.1.2 定制错误处理逻辑

  • 自定义错误页面
  • error/4xx.html error/5xx.html;有精确的错误状态码页面就匹配精确,没有就找 4xx.html ;如果都没有就触发空白页
  • @ControllerAdvice+@ExceptionHandler 处理全局异常
  • @ResponseStatus+自定义异常
  • 底层是ResponseStatusExceptionResolver,把responsestatus注解的信息组装成ModelAndView返回;底层调用 .sendError(statusCode, resolverReason);
  • Spring底层的异常,如:参数类型转换异常;DefaultHandlerExceptionResolver处理框架底层的异常
  • response.sendError(HttpServletResponse.SC_BAD_REQEUST, ex.getMessage)

  • 自定义需要实现 HandlerExceptionResolver 处理异常,可以作为默认的全局异常处理规则
  • ErrorViewResolver实现自定义处理异常
  • response.sedError;error请求就会转给controller
  • 异常没有任何方法能处理。tomcat底层 response.sendError。error请求转给controller
  • basicErrorController 要去的页面地址是 ErrorViewResolver

2.1.3 异常处理原理

  • ErrorMvcAutoAConfiguraion 自动配置异常处理规则
  • 容器中的组件:类型DefaultErrorAttributes-> iderrorAttributes
  • DefaultErrorAttributes:定义错误页面中可以包含哪些数据
  • 容器中的组件:类型 BasicErrorController -> id basicErrorController
  • 处理默认 /error 路径的请求:页面响应 new ModelAndView(“error”,model)
  • 容器中有组件View -> id是error;(响应默认错误页)
  • 容器中放组件 BeanNameViewResolver(视图解析器);按照返回的视图名作为组件的id去容器中找View对象
  • 容器中的组件:类型 DefaultErrorViewResolver -> id conventionErrorViewResolver
  • 如果发生错误,会以HTTP的状态码作为视图页地址(viewName),找到真正大页面
  • error/stuts.viewName(404、5xx).html

如果想要返回页面;就会找error视图 StaticView。(默认是白页)

2.1.4 异常处理步骤流程

  1. 执行目标方法,目标方法运行期间有任何异常都会被 cath,而且标注当前请求结束;并且用 dispatchExeption
  2. 进入视图解析流程(页面渲染)
  3. mv = processHandlerException处理 handler 方法异常,处理完成返回 ModelAndView;
  1. 遍历所有 handlerExceptionResolvers,看谁能处理当前异常【处理器异常解析器】
  2. 系统默认的异常解析器;
  1. DefaultErrorAttributes
  2. HandlerExeptionResolverComposite
  1. ExceptionHandlerExeptionResolver
  2. ResponseStatusExeptionResolver
  3. DefaultHanderExeptionResolver
  1. DefaultErrorAttuibute 先来处理异常,把异常信息保存到request域,并且返回null;
  2. 默认没有任何方法能处理异常,所以异常会被抛出
  1. 如果没有任何方法能处理,最终底层就会发生 /error 请求
  2. 解析错误视图;遍历所有的 ErrorViewResolver 看谁能解析
  3. 默认的 DefaultErrorViewResolver 作用是把响应状态码作为错误页的地址,error/500.html
  4. 模板引擎最终响应这个页面 error/500.html

3. 原生组件注入(Servlet、Filter、Listener)

3.1 使用 Servlet API

@ServletComponentScan(“com.renex.admin”):指定原生Servlet组件都放在哪里

@WebServlet(urlPatterns = “/my”):直接响应,没有Spring的拦截器

@WebFilter(urlPatterns = {“/my”}):拦截指定路径下的所有请求

@WebListener:声明的类是一个 监听类

3.2 使用 RegistrationBean

使用 ServletRegistrationBeanFilterRegistrationBeanServletListenerRegistrationBean

@Configuration
public class MyRegistConfig {
    @Bean
    public ServletRegistrationBean myServlet(){
        MyServlet myServlet = new MyServlet();
        return new ServletRegistrationBean(myServlet,"/my");
    }
    @Bean
    public FilterRegistrationBean myFilter(){
        MyFilter myFilter = new MyFilter();
        // 方式一:
//        return new FilterRegistrationBean(myFilter,myServlet());// 拦截myServlet()返回的全部路径
        // 方式二:
        FilterRegistrationBean filterRegistrationBean = new FilterRegistrationBean(myFilter);
        filterRegistrationBean.setUrlPatterns(Arrays.asList("/my","/my01"));
        return filterRegistrationBean;
    }
    @Bean
    public ServletListenerRegistrationBean myListener(){
        MyListener myListener = new MyListener();
        return new ServletListenerRegistrationBean(myListener);
    }
}

3.3 DispatchServlet 注入原理

3.3.1 DispatchServlet 如何注册进容器?

  • 容器中自动配置了 DisptacherServlet 属性并绑定到 WebMvcProperties;
    对应的配置文件的配置项spring.mvc
  • 通过 ServletRegistrationBean 把 DisptacherServlet 配置进来

默认映射的是 / 路径

多个servlet都能处理到同一层路径,精确优先原则

4. 嵌入式 Web 容器

4.1 切换嵌入式Servlet容器

  • 默认支持的 webServer
  • Tomcat,Jetty 或 Undertow
  • ServletWebServerApplicationContext 容器启动寻找 ServletWEbServerFactory 并引导创建服务器
  • 切换服务器
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-web</artifactId>
  
    <!-- 排除默认的 Tomcat 服务器 -->
    <exclusions>
        <groupId>org.springframework.boot</groupId>
        <artifactid>spring-boot-starter-tomcat</artifactid>
    </exclusions>
</dependency>
<dependency>
    <!-- 设置 undertow 服务器场景包 -->
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-undertow</artifactId>
</dependency>
  • 原理:
  • SprigBoot 应用启动,发现当前是 Web 应用。web场景包-导入 tomcat
  • web 应用会创建一个 web 版的 ioc 容器(ServletWebServerApplicationContext)
  • 在 ioc 启动时,寻找 servletServerFactory(Servlet 的 web 服务器工厂 -> Servlet 的 web 服务器 )
  • SpringBoot 底层默认有很多的 WebServer 工厂
  • 底层直接会有一个自动配置类:ServletWebServerFactoryAutoConfiguraion
  • ServletWebServerFactoryAutoConfiguraion 导入了 ServletWebServerFactoryConfiguration(配置类)
  • ServletWebServerFactoryConfigration 配置类根据动态判断系统中到底导入了哪个 Web 服务器的包(默认 Tomcat),容器中就有 TomcatServletWebServerFactory
  • TomcatServletWebServerFactory 创建出 Tomcat 服务器并启动;
  • TomcatWebServer 的构造器,它拥有初始化方法initialize
  • 内嵌服务器就是手动把启动服务器的代码调用(tomcat 核心 jar 包存在)

4.2 定制 Servlet 容器

  • 实现 WebServerFactoryCustomizer
  • 修改配置文件 server.xxx
  • 直接自定义 CongfigurableServletWebServerFactory

xxxxxxCustomizer:定制化器,可以该变 xxxxxx 的默认规则

5. 定制化原理

5.1 定制化的常见方式

  • 修改配置文件
  • xxxxxCustomizer
  • 编写自定义的配置类 xxConfiguratin + @Bean 替换、增加容器中的默认组件;视图解析器
  • web应用 实现 WebMvcConfigurer 即可定制化 web 功能 + @Bean 给容器中再扩展一些组件
@Configuration
public class AdminWebConfig impements WebMvcConfigurer
  • @EnableWebMvc+ @WebMvcConfigurer —— @Bean 可以全面接管 SpringMVC,所有规则全部自己重写配置;实现定制和扩展功能原理:
  1. WebMvcAutoConfiguration 默认的 SpringMVC 的自动配置功能类。包括实现,静态资源、欢迎页…功能
  2. 一旦使用 @EnableWebMvc 会 @Import(DelegatingWebMvcConfiguration.class)
  3. DelegationWebMvcConfiguration的作用:只保证 SpringMVC 最基本的使用
  1. 把所有系统中的 WebMvcConfigurer 拿来。所有功能的定制都是这些 合起来一起生效
  2. 自动配置了一些非常底层的组件。RequestMappingHandlerMapping。这些组件依赖的组件都是从容器中获取
  1. WebMvcAutoConfiguration 里面的配置要能生效必须
    @ConditionalOnMissingBean(WebMvcConfigurationSupport.class)
  2. @EnableWebMvc 导致了 WebMvcAutoConfiguration 没有生效
    因为一旦声明了@EnableWebMvc,由于该注解会自动引入DelegatingWebMvcConfiguration.class,它会将 WebMvcAutoConfiguration 删除,所以导致了 WebMvcAutoConfiguration 没有生效
  • ······

5.2 原理分析套路

场景starter - xxxxAutoConfiguration - 导入xxx组件 - 绑定xxxProperties - 绑定配置文件项

6. 数据访问

6.1 SQL

6.1.1 数据源的自动配置

6.1.1.1 导入JDBC 场景

<dependency>
      <groupId>org.springframework.boot</groupId>
      <artifactId>spring-boot-starter-data-jdbc</artifactId>
</dependency>

没有数据库驱动?官方不知道我们接下来要操作的数据库

数据库版本和驱动版本对应,SpringBoot 默认会有驱动版本仲裁

导入驱动:

<dependency>
     <groupId>mysql</groupId>
     <artifactId>mysql-connector-java</artifactId>
     <version>8.0.30</version>
</dependency>
<!--
想要修改版本
1. 直接引入具体版本(maven的就近依赖原则)
2. 重写声明版本(maven的属性的就近优先原则)
-->
 <properties>
     <java.version>11</java.version>
     <mysql.version>8.0.30</mysql.version>
</properties>

6.1.1.2 分析自动配置

6.1.1.2.1 自动配置的类
  • DataSourceAutoConfiguration:数据源的自动配置
  • 修改数据源相关的配置:spring.datasource
  • 数据库连接池的配置,是自己容器中没有DataSource才自动配置的
  • 底层默认配置好的连接池是:HikariDataSource
@Configuration(
    proxyBeanMethods = false
)
@Conditional({DataSourceAutoConfiguration.PooledDataSourceCondition.class})
@ConditionalOnMissingBean({DataSource.class, XADataSource.class})
@Import({Hikari.class, Tomcat.class, Dbcp2.class, Generic.class, DataSourceJmxConfiguration.class})
protected static class PooledDataSourceConfiguration {
    protected PooledDataSourceConfiguration() {
    }
}
  • DataSourceTransctionManagerAutoConfiguration:事务管理器的自动配置
  • JdbcTemplateAutoConfiguration:JdbcTemplate的自动配置,可以对数据库进行crud
  • 可以修改整个配置项 @ConfigurationProperties(prefix = “spring.jdbc”) 来修改jdbcTemplate
  • JndiDataSourceAutoConfiguration:Jndi的自动配置
  • XADataSourceAutoConfiguration:分布式事务相关的

6.1.1.3 修改配置项

spring:
  datasource:
    url: jdbc:mysql://localhost:3306/test_1?serverTimezone=UTC
    username: root
    password: root
    driver-class-name: com.mysql.cj.jdbc.Driver
# 超时处理;此处意思:当查询时间超过 3 秒视为查询超时
spring:
  jdbc:
    template:
      query-timeout: 3 #单位秒

6.1.1.4 测试

@Slf4j
@SpringBootTest
class SpringbootWebAdminApplicationTests {
    @Autowired
    JdbcTemplate jdbcTemplate;
    @Test
    void contextLoads() {
        Long aLong = jdbcTemplate.queryForObject("select count(*) from person", long.class);
        log.info("记录总数"+aLong);
    }
}

6.1.2 使用 Druid 数据源

6.1.2.1 Druid 官方 github 地址

Github - Druid

整合第三方技术的两种方式

  • 自定义
  • starter

6.1.2.2 自定义方式

6.1.2.2.1 创建数据源
<dependency>
    <groupId>com.alibaba</groupId>
    <artifactId>druid</artifactId>
    <version>1.2.11</version>
</dependency>

6.1.3 整合 MyBatis 操作

https://github.com/mybatis

SpringBoot官方的Starter:spring-boot-starter-*

第三方的:*-spring-boot-starter

6.1.3.1 配置模式:

6.1.3.1.1 引入配置文件
<dependency>
    <groupId>org.mybatis.spring.boot</groupId>
    <artifactId>mybatis-spring-boot-starter</artifactId>
    <version>2.2.2</version>
</dependency>

6.1.3.1.2 配置模式
  • 全局配置文件
  • SqlSessionFactory:会自动配置
  • SqlSession:自动配置了 SqlSessionTemplate 组合了 SqlSession
  • Mapper:只要写的操作myBatis的接口标注了@Mapper就会备自动扫描进来

可以修改配置文件中 mybatis 的配置文件

# 配置 mybatis 规则
mybatis:
  config-location: classpath:mybatis/mybatis-config.xml
  mapper-locations: classpath:mybatis/mapper/*.xml
  
# Mapper接口 -> 绑定xml
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper
        PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.renex.admin.mapper.PersonMapper">
    <select id="getPerson" resultType="com.renex.admin.pojo.Person">
        select * from person where id = #{id}
    </select>
</mapper>

注意事项:

# 配置 mybatis 规则
mybatis:
#  config-location: classpath:mybatis/mybatis-config.xml
  mapper-locations: classpath:mybatis/mapper/*.xml
  # 开启驼峰命名转换
  configuration: # 指定全局配置文件中的相关配置项
    map-underscore-to-camel-case: true

可以不写全局配置文件,所有全局配置文件都放在configuration配置项中即可

使用了 properties(yaml) 就不能使用 xml 配置文件,两者选一个

6.1.3.1.3 步骤:
  1. 导入 mybatis 官方 starter
  2. 编写 mapper 接口。必须标注 @Mapper 注解
  3. 编写 sql 映射文件并绑定mapper接口
  4. 在 application.yaml 中指定 Mapper 配置文件的位置,以及指定全局配置文件的信息(建议:直接配置在mybatis.configuration)

6.1.3.2 注解模式:

与原生mybatis使用并无两样

6.1.3.3 混合模式:

在一个服务类中可以使用注解也可以使用配置模式

7. 单元测试

7.1 JUnit5

SpringBoot 2.2.0 版本开始引入 JUnit5 作为单元测试默认库

作为最小的版本 JUnit 框架,JUnit5 与之前的版本的 Junit 框架有很大的不同。由三个不同的子项目的不同模块组成

Junit 5 = JUnit Platform + Junit Jupiter + Junit Vintage

Junit Platform:Junit Platform 是在 JVM 上启动测试框架的基础,不仅支持 Junit 自制的测试引擎,其他测试引擎也都可以接入。

Junit Jupiter:Junit Jupiter 提供了 JUnit5 的新的编程模型,是Junit5新特性的核心。内部 包含了一个测试引擎,用于在Junit Platform 上运行

Junit Vintage:由于 Junit 已经发展多年,为了照顾老的项目,Junit Vintage 提供了兼容Junit4.x,Junit3.x的测试引擎

SpringBoot2.4 以上移除了默认对 Vintage 的依赖。如果需要兼容 junit4 需要自行引入(不能使用Junit4的功能)

如果需要继续兼容 Junit4 需要自行引入 vintage

<dependency>
     <groupId>org.springframework.boot</groupId>
     <artifactId>spring-boot-test</artifactId>
     <scope>test</scope>
</dependency>

现在版本:

@SpringBootTest
class Boot05WebAdminApplicationTestsO{
    
    @Test
    void contentLoads(){
        
    }
    
}

以前:

@SpringBootTest + @RunWith(SpringTest.class)

SpringBoot 整合 Junit 以后:

  • 编写测试方法:@Test 标注(注意需要使用Junit5版本的)
  • Junit类具有Spring的功能,@Autowired、比如 @Transactional 标注测试方法,测试完成后自动回滚

7.2 JUnit5 常用注解

Junit5 的注解与JUnit4的注解有所变化。详细更新或注解介绍:JUnit 5 User Guide

注解名称: 详情用法:
@Test 表示方法是测试方法。但是与Junit4的@Test不同。它的职责非常单一不能声明任何属性,拓展的测试将会由Jupiter提供测试
@ParmeterizedTest 表示方法是参数化测试
@RepeatedTest 表示方法可以重复执行
@DispalyName 为测试类或者测试方法设置展示名称
@BeforeEach 表示在每个单元测试之前执行
@AfterEach 表示在每个单元测试之后执行
@BeforeAll 表示在所有单元测试之前执行
@AfterAll 表示在所有单元测试之后执行
@Tag 表示单元测试类别,类似于JUnit4中的@Categories
@Disabled 表示测试类或测试方法不知想,类似于JUnit4中的@Ignore
@Timeout 表示测试方法运行如果超过了指定时间将会返回错误
@ExtendWith 为测试类或测试方法提供扩展类引用。集合了 SpringBoot 可以使用 @SpringBootTest 进行代替,但是会启动 SpringBoot 的容器功能

7.3 断言(assertions)

断言(assertions)是测试方法中的核心部分,用来对测试需要满足的条件进行验证。这些断言方法都是 org.junit.jupiter.api.Assertions 的静态方法。JUnit5 内置的断言可以分成如下几个类别:

检查业务逻辑返回的数据是否合理

所有的测试运行结束以后,会有一个详细的测试报告;

7.3.1 简单断言

用来对单个值进行简单的验证,如:

方法 说明
assertEquals 判断两个对象或两个原始类型是否相等
assertNotEquals 判断两个对象或两个原始类型是否不相等
assertSame 判断两个对象引用是否指向同一个对象
assertNotSame 判断两个对象引用是否指向不同的对象
assertTrue 判断给定的布尔值是否为 true
assertFalse 判断给定的布尔值是否为 false
assertNull 判断给定的对象引用是否为 null
assertNotNull 判断给定的对象引用是否不为 null

7.3.2 组合断言

assertAll 方法接收多个 org.junit.jupiter.api.Executable 函数式接口的实例作为要验证的断言,可以通过 lambda 表达式很容的提供这些断言

@DisplayName("组合断言")
@Test
void all(){
    /**
     * 所有断言需要全部成功
     */
    assertAll("test",
            ()-> assertTrue(true && false),
            ()-> assertEquals(1,1)
            );
}

7.3.3 异常断言

在 JUnit4 使其,想要测试方法的异常情况时,需要用 @Rule 注解的ExpectedException 变量还是比较麻烦的。而JUnit5提供了一种新的断言方式 Assertions.assertThrows(),配合函数式编程就可以进行使用

@Test
@DisplayName("异常断言")
void testException(){
    // 断言业务逻辑一定出现异常
    assertThrows(ArithmeticException.class, ()->{
        int i = 1/0;
    },"业务逻辑正常运行!!");
}

7.3.4 超时断言

JUnit5 还提供了 Assertions.asserTimeout() 为测试方法设置了超时时间

@Test
@DisplayName("超时断言")
void testTimeoutAssert(){
    /**
     * 运行时间已超出 1000 毫秒
     */
    assertTimeout(Duration.ofMillis(1000),()->{
        Thread.sleep(1100);
    });
}

7.3.5 快速失败

通过 fail 方法直接使得测试失败

@Test
@DisplayName("快速失败")
void testFail(){
    System.out.println("测试开始.......");
    fail("直接宣告测试失败!");
    System.out.println("测试正在运行....");
    System.out.println("测试结束......");
}

7.4 前置条件(assumptions)

JUnit5 中的前置条件(assumptions 【假设】)类似于断言,不同之处在于不满足的断言会使得测试方法失败,而不满足的前置条件只会使得测试方法的执行终止。前置条件可以看成是测试方法执行的前提,当该前提不满足时,就没有继续执行的必要。

@Test
@DisplayName("测试前置条件")
void testAssumptions(){
    Assumptions.assumeTrue(assumeIsTrue(),"结果不是true");
    System.out.println("11");
}
boolean assumeIsTrue(){
    return false;
}

assumeTrue 和 assumFalse 确保给定的条件为 true 或 false,不满足条件会使得测试执行种植。assumingThat 的参数是表示条件的布尔值和对应的 Executable 接口的实现对象。只有田间满足时,Executable 对象才会被执行;当条件不满足时,测试执行并不会终止

7.5 嵌套测试

JUnit5 可以通过 Java 中的内部类和 @Nested 注解实现嵌套测试,从而可以更好的把相关的测试方法组织在一起。在内部类中可以使用 @BeforEach 和 @AfterEach 注解,而且嵌套的层次没有限制

内层的 Test 可以驱动外层的 Befor(After)Each / All 之类的方法 提前 / 之后 运行

7.6 参数化测试

参数化测试是 JUnit5 很重要的一个新特性,它使得用不同的参数多次运行测试成为了可能,也为我们的单元测试带来许多遍历。

利用 @ValueSrouce 等注解,指定入参,我们将可以使用不同的参数进行多次单元测试,而不是每新增一个参数就新增一个单元测试。

注解名称 说明
@ValueSource 为参数化测试指定入参来源,支持八大基础类以及String类型,Class类型
@NullSource 表示为参数化测试提供一个null的入参
@EnumSource 表示为参数化测试提供一个枚举入参
@CsvFileSource 表示读取指定CSV文件内容作为参数化测试入参
@MethodSource 表示读取指定方法的返回值作为参数化测试入参(注意方法返回需要是一个流)

当然如果参数化测试仅仅只能做到指定普通的入参还达不到让我觉得惊艳的地步。真正强大之处在于他可以支持外部的各类入参。如:CSV,YML,JSON 文件甚至方法的返回值也可以作为入参。只需要去实现 ArgumentsProvider 接口,任何外部文件都可以作为它的入参。

@ParameterizedTest
@DisplayName("参数化测试")
@ValueSource(ints = {1,2,3,4,5,6})
void testParameterize(int i){
    System.out.println(i);
}
@ParameterizedTest
@DisplayName("参数化测试")
@MethodSource("stringProvider")// 方法名
void testParameterize(String i){
    System.out.println(i);
}
static Stream<String> stringProvider(){
    return Stream.of("apple","bannana","atguigu");
}

8. ❤️👌SpringBoot 专栏前文回顾

9. 💕👉 其他好文推荐

目录
相关文章
|
1月前
|
XML JSON Java
【SpringBoot(三)】从请求到响应再到视图解析与模板引擎,本文带你领悟SpringBoot请求接收全流程!
Springboot专栏第三章,从请求的接收到视图解析,再到thymeleaf模板引擎的使用! 本文带你领悟SpringBoot请求接收到渲染的使用全流程!
174 3
|
5月前
|
人工智能 Java 测试技术
Spring Boot 集成 JUnit 单元测试
本文介绍了在Spring Boot中使用JUnit 5进行单元测试的常用方法与技巧,包括添加依赖、编写测试类、使用@SpringBootTest参数、自动装配测试模块(如JSON、MVC、WebFlux、JDBC等),以及@MockBean和@SpyBean的应用。内容实用,适合Java开发者参考学习。
581 0
|
4月前
|
Java 测试技术 Spring
简单学Spring Boot | 博客项目的测试
本内容介绍了基于Spring Boot的博客项目测试实践,重点在于通过测试驱动开发(TDD)优化服务层代码,提升代码质量和功能可靠性。案例详细展示了如何为PostService类编写测试用例、运行测试并根据反馈优化功能代码,包括两次优化过程。通过TDD流程,确保每项功能经过严格验证,增强代码可维护性与系统稳定性。
216 0
|
5月前
|
人工智能 Java 测试技术
SpringBoot 测试实践:单元测试与集成测试
在 Spring Boot 测试中,@MockBean 用于创建完全模拟的 Bean,替代真实对象行为;而 @SpyBean 则用于部分模拟,保留未指定方法的真实实现。两者结合 Mockito 可灵活控制依赖行为,提升测试覆盖率。合理使用 @ContextConfiguration 和避免滥用 @SpringBootTest 可优化测试上下文加载速度,提高测试效率。
326 6
深入实践springboot实战 蓄势待发 我不是雷锋 我是知识搬运工
springboot,说白了就是一个集合了功能的大类库,包括springMVC,spring,spring data,spring security等等,并且提供了很多和可以和其他常用框架,插件完美整合的接口(只能说是一些常用框架,基本在github上能排上名次的都有完美整合,但如果是自己写的一个框架就无法实现快速整合)。
|
Java 数据安全/隐私保护
Neo4j【付诸实践 01】SpringBoot集成报错org.neo4j.driver.exceptions.ClientException:服务器不支持此驱动程序支持的任何协议版本(解决+源代码)
Neo4j【付诸实践 01】SpringBoot集成报错org.neo4j.driver.exceptions.ClientException:服务器不支持此驱动程序支持的任何协议版本(解决+源代码)
764 1
|
缓存 Java Maven
Java本地高性能缓存实践问题之SpringBoot中引入Caffeine作为缓存库的问题如何解决
Java本地高性能缓存实践问题之SpringBoot中引入Caffeine作为缓存库的问题如何解决
593 1
|
Java 应用服务中间件 开发者
深入探索并实践Spring Boot框架
深入探索并实践Spring Boot框架
217 2
|
缓存 Java Spring
Java本地高性能缓存实践问题之在Spring Boot中启用缓存支持的问题如何解决
Java本地高性能缓存实践问题之在Spring Boot中启用缓存支持的问题如何解决
178 0
|
JavaScript Java 测试技术
返家乡”高校暑期社会实践微信小程序+springboot+vue.js附带文章和源代码设计说明文档ppt
返家乡”高校暑期社会实践微信小程序+springboot+vue.js附带文章和源代码设计说明文档ppt
120 0