Springboot测试篇 | Junit5

这篇具有很好参考价值的文章主要介绍了Springboot测试篇 | Junit5。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。


PS:文章将持续更新修订


一. 前言&介绍

简单介绍吧本篇文章将从Junit5到一些Springboot的特殊场景测试配置。
JUnit5简单介绍:Spring Boot2.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:由于JUint已经发展多年,为了照顾老的项目,JUnit Vintage提供了兼容JUnit4.x,Junit3.x的测试引擎。

Springboot测试篇 | Junit5
值得注意的是:SpringBoot 2.4 以上版本移除了默认对 Vintage 的依赖,如果需要兼容junit4需要自行引入(不能使用junit4的功能 @Test):

<dependency>
    <groupId>org.junit.vintage</groupId>
    <artifactId>junit-vintage-engine</artifactId>
    <scope>test</scope>
    <exclusions>
        <exclusion>
            <groupId>org.hamcrest</groupId>
            <artifactId>hamcrest-core</artifactId>
        </exclusion>
    </exclusions>
</dependency>
1. IDEA默认测试目录

默认我们创建好Springboot的项目后都会生成一个默认的配置类
Springboot测试篇 | Junit5
内容如下:

@SpringBootTest
class JunitCsdnApplicationTests {
    @Test
    void contextLoads() {
    }
}

由@SpringBootTest注解进行标注后该类就是Springboot的单元测试类了
提供的依赖也是Springboot帮助我们自动生成的:

<dependency>
     <groupId>org.springframework.boot</groupId>
     <artifactId>spring-boot-starter-test</artifactId>
     <scope>test</scope>
</dependency>
2. 值得一提的小bug

在我们使用springboot项目进行测试时,假如我们是前端项目,并没有导入数据源操作数据库启动单元测试方法时可能会遇到下面这个错误:
springBoot Error creating bean with name 'dataSource' defined in class path resource
原因是:spring boot会默认加载org.springframework.boot.autoconfigure.jdbc.DataSourceAuto Configuration类,DataSourceAutoConfiguration又使用了@Configuration注解向spring注入了dataSource bean,但是因为工程中没有关于dataSource相关的配置信息,当spring创建dataSource bean因缺少相关的信息就会报错。
解决方法:启动工程时排除:DataSourceAutoConfiguration即可,如在@SpringBootApplication启动注解上加 exclude={DataSourceAutoConfiguration.class}
Springboot测试篇 | Junit5

3. IDEA测试技巧

在IDEA的面板的右侧有一个Maven的图标:
Springboot测试篇 | Junit5
点击展开后选择我们的项目点击【生命周期】按住ctrl键我们可以指定运行的生命周期:
Springboot测试篇 | Junit5
像上面这样运行完clean周期后执行test周期会将我们编写的测试用例全部执行一遍

二. Junit5单元测试

1. 常用注解

下面将以一些常用注解为切入点简单介绍Junit5的基本使用,更多注解的使用方法可以自行搜索相关资料或者查询官网。

1. @Test

表示方法是测试方法。但是与JUnit4的@Test不同,他的职责非常单一不能声明任何属性,拓展的测试将会由Jupiter提供额外测试:
Springboot测试篇 | Junit5

2. @Autowired

将Spring中的容器注入到环境中,方便在单元测试中使用Spring中的容器。
Springboot测试篇 | Junit5

3. @Transactional

标注@Transactional注解主要是为了防止数据污染,如果单元测试方法中有对数据库进行操作,执行完测试方法后自动进行数据回滚防止对数据的污染,但是这个注解在开发中慎用,会几种情况下该注解会失效,这个感觉兴趣的朋友可以去搜索一下相关文章。
Springboot测试篇 | Junit5
但是使用这个注解需要引入Spring boot提供的JDBC或JPA依赖:

<dependency>
   <groupId>org.springframework.boot</groupId>
   <artifactId>spring-boot-starter-jdbc</artifactId>
   <scope>test</scope>
</dependency>
 
<dependency>
   <groupId>org.springframework.boot</groupId>
   <artifactId>spring-boot-starter-data-jpa</artifactId>
   <scope>test</scope>
</dependency>
4. @DisplayName

为测试方法起名,既可以在方法上进行标注也可以在类上面进行标注:

@SpringBootTest
@DisplayName("测试类")
class JunitCsdnApplicationTests {

    @DisplayName("功能测试")
    @Test
    void contextLoads() {
        System.out.println("靓仔,又来学JAVA了?");
    }

}

运行效果:
Springboot测试篇 | Junit5

5. @BeforeEach

该注解标注的方法,在每个单元测试之前都会执行一次,通常用来加载其他单元测试所用资源。

6. @AfterEach

该注解标注的方法,在每个单元测试执行之后都会自动执行一次,通常用来释放其他单元测试造成的内存

7. @BeforeAll

表示在所有单元测试之前执行 ,通常只有在一次性启动整个类的时候才会执行这个注解标注的方法。
Springboot测试篇 | Junit5
值得注意的是该注解标注的方法必须是一个静态方法,也就是必须是用static标注的方法

8. @AfterAll

表示在所有单元测试之后执行,通常只有在一次性启动整个类的时候才会执行这个注解标注的方法。
Springboot测试篇 | Junit5
值得注意的是该注解标注的方法必须是一个静态方法,也就是必须是用static标注的方法

9. @Tag

表示单元测试类别,类似于JUnit4中的@Categories

10. @Disabled

表示测试类或测试方法不执行,类似于JUnit4中的@Ignore,也就是达到一个禁用的效果。

11. @Timeout

表示测试方法运行如果超过了指定时间将会返回错误
Springboot测试篇 | Junit5

12. @RepeatedTest

可以使方法重复测试,我们可以指定方法重复的次数:
Springboot测试篇 | Junit5
上面的意思表示上面的单元测试执行后会循环执行五次

2. 断言

断言(assertions)是测试方法中的核心部分,用来对测试需要满足的条件进行验证。
这些断言方法都是 org.junit.jupiter.api.Assertions 的静态方法,检查业务逻辑返回的数据是否合理。
所有的测试运行结束以后,会有一个详细的测试报告;
JUnit 5 内置的断言可以分成如下几个类别:

1. 简单断言

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

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

如果断言失败如下面情况:
Springboot测试篇 | Junit5
Idea会给我们爆出错误信息
Springboot测试篇 | Junit5
值得注意的是: 只要前面的断言失败后面的代码都不会被执行,参数一般都是期望值,参数二是判断值,二参数三一般都是断言错误后的提示信息。

2. 数组断言

通过 assertArrayEquals 方法来判断两个对象或原始类型的数组是否相等

@Test
@DisplayName("array assertion")
public void array() {
 assertArrayEquals(new int[]{1, 2}, new int[] {1, 2});
}
3. 组合断言

assertAll 方法接受多个 org.junit.jupiter.api.Executable 函数式接口的实例作为要验证的断言,可以通过 lambda 表达式很容易的提供这些断言,全部断言成功才算成功,有一个失败都算失败:

@Test
@DisplayName("assert all")
public void all() {
// Math 是组名
 assertAll("Math",
    () -> assertEquals(2, 1 + 1),
    () -> assertTrue(1 > 0)
 );
}
4. 异常断言

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

@Test
@DisplayName("异常测试")
public void exceptionTest() {
    ArithmeticException exception = Assertions.assertThrows(
           //扔出断言异常
            ArithmeticException.class, () -> System.out.println(1 % 0),"出现数学运算异常");

}
5. 超时异常

Junit5还提供了Assertions.assertTimeout() 为测试方法设置了超时时间:

@Test
@DisplayName("超时测试")
public void timeoutTest() {
    //如果测试方法时间超过1s将会异常
    Assertions.assertTimeout(Duration.ofMillis(1000), () -> Thread.sleep(500));
}
6. 快速失败

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

@Test
@DisplayName("fail")
public void shouldFail() {
 fail("This should fail");
}

3. 前置条件

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

@DisplayName("前置条件")
public class AssumptionsTest {
 private final String environment = "DEV";
 
 @Test
 @DisplayName("simple")
 public void simpleAssume() {
    assumeTrue(Objects.equals(this.environment, "DEV"));
    assumeFalse(() -> Objects.equals(this.environment, "PROD"));
 }
 // simpleAssume方法中如果assumeTrue的结果为True才会继续向下执行,如果结果非预期则会爆出错误
 // 下面的测试逻辑也不会被执行

4. 参数化测试

参数化测试是JUnit5很重要的一个新特性,它使得用不同的参数多次运行测试成为了可能,也为我们的单元测试带来许多便利。
利用@ValueSource等注解,指定入参,我们将可以使用不同的参数进行多次单元测试,而不需要每新增一个参数就新增一个单元测试,省去了很多冗余代码。

1. @ParameterizedTest

使用@ParameterizedTest注解进行标注后表示该测试不是一个不同的单元测试而是一个参数化测试,是Junit5参数化测试的重要注解。

2. @ValueSource

为参数化测试指定入参来源,支持八大基础类以及String类型,Class类型:

@ParameterizedTest
@ValueSource(strings = {"one", "two", "three"}) // 依次传递给下面的形参,执行3次
@DisplayName("参数化测试1")
public void parameterizedTest1(String string) {
    System.out.println(string);
    Assertions.assertTrue(StringUtils.isNotBlank(string));
}
3. @MethodSourc

表示读取指定方法的返回值作为参数化测试入参(注意方法返回需要是一个流),例如:

static Stream<String> streamtext(){
      return Stream.of("牛","马","人")
    }
    @ParameterizedTest
    @DisplayName("参数化测试1")
    @MethodSource("streamtext")
    public void parameterizedTest(String string) {
        System.out.println(string);
    }
4. 加载测试配置类

学习过Spring的知识,我们都知道,其实一个spring环境中可以设置若干个配置文件或配置类,若干个配置信息可以同时生效。现在我们的需求就是在测试环境中再添加一个配置类,然后启动测试环境时,生效此配置就行了。其实做法和spring环境中加载多个配置信息的方式完全一样。具体操作步骤如下:
步骤①:在测试包test中创建专用的测试环境配置类:

@Configuration
public class MsgConfig {
    @Bean
    public String msg(){
        return "bean msg";
    }
}

上述配置仅用于演示当前实验效果,实际开发可不能这么注入String类型的数据

步骤②:在启动测试环境时,导入测试环境专用的配置类,使用@Import注解即可实现

@SpringBootTest
@Import({MsgConfig.class})
public class ConfigurationTest {

    @Autowired
    private String msg;

    @Test
    void testConfiguration(){
        System.out.println(msg);
    }
}

到这里就通过@Import属性实现了基于开发环境的配置基础上,对配置进行测试环境的追加操作,实现了1+1的配置环境效果。这样我们就可以实现每一个不同的测试用例加载不同的bean的效果,丰富测试用例的编写,同时不影响开发环境的配置。

5. 随机值

对于测试用例的数据固定书写肯定是不合理的,springboot提供了在配置中使用随机值的机制,确保每次运行程序加载的数据都是随机的,具体如下:

testcase:
  book:
    id: ${random.int}
    id2: ${random.int(10)}
    type: ${random.int!5,10!}
    name: ${random.value}
    uuid: ${random.uuid}
    publishTime: ${random.long}

Springboot测试篇 | Junit5
当前配置就可以在每次运行程序时创建一组随机数据,避免每次运行时数据都是固定值的尴尬现象发生,有助于测试功能的进行。数据的加载按照之前加载数据的形式,使用@ConfigurationProperties注解即可:

@Component
@Data
@ConfigurationProperties(prefix = "testcase.book")
public class BookCase {
    private int id;
    private int id2;
    private int type;
    private String name;
    private String uuid;
    private long publishTime;
}

5. Web环境测试

1. 环境搭建

测试类中启动web环境:每一个springboot的测试类上方都会标准@SpringBootTest注解,而注解带有一个属性,叫做webEnvironment。通过该属性就可以设置在测试用例中启动web环境,具体如下:

@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)
public class WebTest {	
}

测试类中启动web环境时,可以指定启动的Web环境对应的端口,springboot提供了4种设置值,分别如下:
Springboot测试篇 | Junit5

  • MOCK:根据当前设置确认是否启动web环境,例如使用了Servlet的API就启动web环境,属于适配性的配置
  • DEFINED_PORT:使用自定义的端口作为web服务器端口
  • RANDOM_PORT:使用随机端口作为web服务器端口
  • NONE:不启动web环境

通过上述配置,现在启动测试程序时就可以正常启用web环境了,建议大家测试时使用RANDOM_PORT,避免代码中因为写死设定引发线上功能打包测试时由于端口冲突导致意外现象的出现。就是说你程序中写了用8080端口,结果线上环境8080端口被占用了,结果你代码中所有写的东西都要改,这就是写死代码的代价。现在你用随机端口就可以测试出来你有没有这种问题的隐患了。
测试环境中的web环境已经搭建好了,下面就可以来解决第二个问题了,如何在程序代码中发送web请求。
测试类中发送请求:对于测试类中发送请求,其实java的API就提供对应的功能,只不过平时各位小伙伴接触的比较少,所以较为陌生。springboot为了便于开发者进行对应的功能开发,对其又进行了包装,简化了开发步骤,具体操作如下:
步骤①:在测试类中开启web虚拟调用功能,通过注解@AutoConfigureMockMvc实现此功能的开启:

@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)
//开启虚拟MVC调用
@AutoConfigureMockMvc
public class WebTest {
}

步骤②:定义发起虚拟调用的对象MockMVC,通过自动装配的形式初始化对象:

@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)
//开启虚拟MVC调用
@AutoConfigureMockMvc
public class WebTest {

    @Test
    void testWeb(@Autowired MockMvc mvc) {
    }
}

步骤③:创建一个虚拟请求对象,封装请求的路径,并使用MockMVC对象发送对应请求:

@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)
//开启虚拟MVC调用
@AutoConfigureMockMvc
public class WebTest {

    @Test
    void testWeb(@Autowired MockMvc mvc) throws Exception {
        //http://localhost:8080/books
        //创建虚拟请求,当前访问/books
        MockHttpServletRequestBuilder builder = MockMvcRequestBuilders.get("/books");
        //执行对应的请求
        mvc.perform(builder);
    }
}

执行测试程序,现在就可以正常的发送/books对应的请求了,注意访问路径不要写http://localhost:8080/books,因为前面的服务器IP地址和端口使用的是当前虚拟的web环境,无需指定,仅指定请求的具体路径即可。

2. web环境请求结果比对

上一节已经在测试用例中成功的模拟出了web环境,并成功的发送了web请求,本节就来解决发送请求后如何比对发送结果的问题。其实发完请求得到的信息只有一种,就是响应对象。至于响应对象中包含什么,就可以比对什么。常见的比对内容如下:

  • 响应状态匹配

    @Test
    void testStatus(@Autowired MockMvc mvc) throws Exception {
        MockHttpServletRequestBuilder builder = MockMvcRequestBuilders.get("/books");
        ResultActions action = mvc.perform(builder);
        //设定预期值 与真实值进行比较,成功测试通过,失败测试失败
        //定义本次调用的预期值
        StatusResultMatchers status = MockMvcResultMatchers.status();
        //预计本次调用时成功的:状态200
        ResultMatcher ok = status.isOk();
        //添加预计值到本次调用过程中进行匹配
        action.andExpect(ok);
    }
    
  • 响应体匹配(非json数据格式)

    @Test
    void testBody(@Autowired MockMvc mvc) throws Exception {
        MockHttpServletRequestBuilder builder = MockMvcRequestBuilders.get("/books");
        ResultActions action = mvc.perform(builder);
        //设定预期值 与真实值进行比较,成功测试通过,失败测试失败
        //定义本次调用的预期值
        ContentResultMatchers content = MockMvcResultMatchers.content();
        ResultMatcher result = content.string("springboot2");
        //添加预计值到本次调用过程中进行匹配
        action.andExpect(result);
    }
    
  • 响应体匹配(json数据格式,开发中的主流使用方式)

    @Test
    void testJson(@Autowired MockMvc mvc) throws Exception {
        MockHttpServletRequestBuilder builder = MockMvcRequestBuilders.get("/books");
        ResultActions action = mvc.perform(builder);
        //设定预期值 与真实值进行比较,成功测试通过,失败测试失败
        //定义本次调用的预期值
        ContentResultMatchers content = MockMvcResultMatchers.content();
        ResultMatcher result = content.json("{\"id\":1,\"name\":\"springboot2\",\"type\":\"springboot\"}");
        //添加预计值到本次调用过程中进行匹配
        action.andExpect(result);
    }
    
  • 响应头信息匹配

    @Test
    void testContentType(@Autowired MockMvc mvc) throws Exception {
        MockHttpServletRequestBuilder builder = MockMvcRequestBuilders.get("/books");
        ResultActions action = mvc.perform(builder);
        //设定预期值 与真实值进行比较,成功测试通过,失败测试失败
        //定义本次调用的预期值
        HeaderResultMatchers header = MockMvcResultMatchers.header();
        ResultMatcher contentType = header.string("Content-Type", "application/json");
        //添加预计值到本次调用过程中进行匹配
        action.andExpect(contentType);
    }
    

​ 基本上齐了,头信息,正文信息,状态信息都有了,就可以组合出一个完美的响应结果比对结果了。以下范例就是三种信息同时进行匹配校验,也是一个完整的信息匹配过程。文章来源地址https://www.toymoban.com/news/detail-404233.html

@Test
void testGetById(@Autowired MockMvc mvc) throws Exception {
    MockHttpServletRequestBuilder builder = MockMvcRequestBuilders.get("/books");
    ResultActions action = mvc.perform(builder);

    StatusResultMatchers status = MockMvcResultMatchers.status();
    ResultMatcher ok = status.isOk();
    action.andExpect(ok);

    HeaderResultMatchers header = MockMvcResultMatchers.header();
    ResultMatcher contentType = header.string("Content-Type", "application/json");
    action.andExpect(contentType);

    ContentResultMatchers content = MockMvcResultMatchers.content();
    ResultMatcher result = content.json("{\"id\":1,\"name\":\"springboot\",\"type\":\"springboot\"}");
    action.andExpect(result);
}

到了这里,关于Springboot测试篇 | Junit5的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • 13.Springboot整合junit5单元测试与生成单元测试覆盖率

    现在基本大公司都要求单元测试了,保证我们代码得质量,而我司更是要求覆盖率要达到60%以上,所以搞一下。 这里有两个方法: 1.使用maven自带得test,idea右侧maven模块执行项目下得test 2.使用cmd命令,在你的项目pom文件所在目录 ,打开cmd,执行如下: 结果如下:打开site文

    2024年02月16日
    浏览(40)
  • springboot项目使用Junit5 + mockito + jacoco 实现单元测试以及代码覆盖率检查

    在创建springboot项目时会默认添加spring-boot-starter-test依赖,其中已经包含了junit、mockito依赖,根据springboot版本的不同junit和mockito的版本也会有所不同 先说一下各自功能: junit只说一点,junt4和junit5的注解不同,使用方式略有差异,其他不赘述了,基本用法都懂。 mockito是mock的

    2023年04月23日
    浏览(58)
  • 单元测试框架——Junit5

    Junit是一个开源的用于Java语言的单元测试框架,也是Java方向使用最广泛的单元测试框架。 在pom.xml中引入Junit5相关依赖 @Test :表示一个方法/用例 BeforeEach :表示被注解的方法在其它所有方法执行前都要执行一遍,也就是说其它方法有3个它就要执行3遍 @BeforeAll :表示被注解的

    2024年02月11日
    浏览(44)
  • Junit5单元测试框架详解

    前面我们学习了Selenium自动化测试框架,但是有的时候测试用例会很多,我们需要一个工具来管理这些测试用例,而Junit就是一个很好的管理工具,简单点来说,Junit就是一个针对Java的单元测试框架; 目录 一. 关于Junit5 二. Junit使用 2.1 添加Maven依赖 2.2 注解 2.3 断言 2.4 套件

    2024年02月06日
    浏览(49)
  • JUnit5-单元测试操作详解

    JUnit 5是JUnit测试框架的下一个主要版本,用于编写和运行单元测试。 与以前版本的 JUnit 不同,JUnit 5 由来自三个不同子项目的多个不同模块组成。 JUnit 5 =  JUnit 平台 +  JUnit Jupiter  +  JUnit Vintage JUnit 平台 是在 JVM 上启动测试框架的基础。它还定义了 TestEngine 用于开发在平台

    2024年04月10日
    浏览(52)
  • 【单元测试】如何使用 JUnit5 框架?

      Junit5是一个用于在Java平台上进行单元测试的框架。JUnit 5 框架主要由三部分组成:JUnit Platform、JUnit Jupiter 和 JUnit Vintage。 JUnit Platform:定义了测试引擎的 API,是 JVM 上用于启动测试框架的基础服务,支持通过 IDE、构建工具、命令行等方式运行单元测试。 JUnit Jupiter:包含

    2024年04月10日
    浏览(46)
  • Junit5+Mockito单元测试详解

    1.宏观层面:AIR原则 A:Automatic(自动化) 全自动执行,输出结果无需人工检查,而是通过断言验证。 I:Independent(独立性) 分层测试,各层之间不相互依赖。 R:Repeatable(可重复) 可重复执行,不受外部环境( 网络、服务、中间件等)影响。 2.微观层面:BCDE原则 B: Bord

    2024年01月17日
    浏览(48)
  • 【测试学习】Junit5的简单使用

    目录 🌟需要知道: 🌟Junit学习 🌈1、常用的注解 🌈2、测试用例的执行顺序 🌈3、参数化 🌈4、断言 🌈5、测试套件 问题1:Selenium与Junit之间的关系?         就像雷锋和雷峰塔的关系,就是没关系。 问题2:为什么学习了Selenium之后还要学习Junit?         Junit是针对

    2024年02月16日
    浏览(32)
  • TestNG和Junit5测试框架梳理

    1. testNG优势 2. testNG常用注解 3. testNG中@Test有哪些参数 举例: 4.  在 TestNG 中实现参数化测试 以Yaml文件为例 创建一个Yaml文件testdata.yaml 获取测试数据及使用 5. 执行顺序 6. testNG断言 7. 失败重试 1. junit5的优势 2. 常用注解 3. TestFactory使用示例 TestFactory其实就是参数化执行同一条

    2024年02月13日
    浏览(36)
  • 单元测试junit(原始版本、Spring Boot各版本、junit5)使用介绍

    🍓 简介:java系列技术分享(👉持续更新中…🔥) 🍓 初衷:一起学习、一起进步、坚持不懈 🍓 如果文章内容有误与您的想法不一致,欢迎大家在评论区指正🙏 🍓 希望这篇文章对你有所帮助,欢迎点赞 👍 收藏 ⭐留言 📝 🍓 更多文章请点击 单元测试 junit各版本 使用介绍 官

    2023年04月16日
    浏览(44)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包