05_SpringBoot_Junit5

本文介绍了SpringBoot2.2.0开始使用JUnit5作为默认单元测试库的情况,详细讲解了JUnit5的构成,包括JUnitPlatform、JUnitJupiter和JUnitVintager。同时展示了如何利用JUnit5的注解如@Autowired和@Transactional进行Spring环境下的测试。文章通过具体的代码示例,演示了@BeforeEach、@AfterEach、@BeforeAll、@AfterAll、@RepeatedTest、@Timeout等生命周期方法,以及断言机制、前置条件(Assumptions)、嵌套测试和参数化测试的用法。

 

springboot 2.2.0开始引入Junit5作为单元测试的默认库
JUnit5和之前的版本有很大的不同,由单个子项目的几个不同模块组成
JUnit Platform ,是在JVM上启动测试框架的技术,不仅支持Junit自己的测试引擎,其他的测试引擎也可以
JUnit Jupiter,提供了Junit5的最新的编程模型,是Junit5 的核心,内部包含了一个测试引擎,用于在Junit Platform上运行
JUnit Vintager: 提供了兼容Junit4/3 的测试引擎

Junit5 = JUnit Platform+ JUnit Jupiter+JUnit Vintager

Junit支持Spring中的注解,测试起来比较方便, @Autowired @Transactional 等

package com.msb;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.msb.mapper.DeptMapper;
import com.msb.pojo.Dept;
import com.msb.service.DeptService;
import org.junit.jupiter.api.*;
import org.junit.jupiter.api.extension.ExtendWith;
import org.junit.platform.commons.annotation.Testable;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.boot.test.context.SpringBootTestContextBootstrapper;
import org.springframework.test.context.BootstrapWith;
import org.springframework.test.context.junit.jupiter.SpringExtension;
import java.util.List;
import java.util.concurrent.TimeUnit;
@SpringBootTest // 使用springboot的容器功能
/*@BootstrapWith(SpringBootTestContextBootstrapper.class)
@ExtendWith({SpringExtension.class})*/
@DisplayName("Junit5测试类")// 测试类描述
class SpringbootMybatisplusApplicationTests2 {
    @Autowired
    private DeptMapper deptMapper;
    @BeforeEach
    public void testForeach(){
        System.out.println("beforeach");
    }
    @AfterEach
    public void testAftereach(){
        System.out.println("aferEach");
    }
    @BeforeAll
    public static void beforeAll(){
        System.out.println("beforall");
    }
    @AfterAll
    public static void aferAll(){
        System.out.println("afterAll");
    }
    @RepeatedTest(3)// 重复测试3次
    @Timeout(value = 10000,unit = TimeUnit.MILLISECONDS)// 超时时间设置
    @DisplayName("Junit测试方法1")
    @Test
    public void test1(){
        System.out.println("a");
        System.out.println(deptMapper);
    }
    @Disabled// 设置不可用
    @DisplayName("Junit测试方法2") // 方法描述
    @Test
    public void test2(){
        System.out.println("b");
    }
}

断言机制
断定某件事情,一定会发生,如果没有发生,那就是出现了问题,所欲的测试运行结束后,会有一个详细的断言报告
用来对测试需要满足的条件进行验证,这些断言方法都是org.junit.jupiter.api.Assertions中的静态方法,
简单断言

package com.msb;
import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.Test;
import org.springframework.boot.test.context.SpringBootTest;
import java.time.Duration;
import java.util.concurrent.TimeUnit;
@SpringBootTest
@DisplayName("Junit5断言测试类")
class SpringbootMybatisplusApplicationTests3 {
    @DisplayName("简单断言1")
    @Test
    public void testAssertions1(){
        int add = add(1, 2);
        Assertions.assertEquals(6,add,"add结果计算错误");
    }
    public int add(int a,int b){
        return a+b;
    }
    @DisplayName("简单断言2")
    @Test
    public void testAssertions2(){
        String s =new String("xxx");
        String s2=new String("abc");
        Assertions.assertEquals(s,s2,"String对象不一样");
    }
    // 组合断言
    @DisplayName("组合断言")
    @Test
    public void testAssertAll(){
        Assertions.assertAll("AssertAll",
                ()-> Assertions.assertTrue(true&& false),
                ()-> Assertions.assertEquals(1,2));
    }
    // 异常断言 认为应该会出现异常
    @DisplayName("异常断言")
    @Test
    public void testAssertException(){
        Assertions.assertThrows(ArithmeticException.class, ()->{ int i=1/0;}, "没有抛出异常");
    }
    // 超时断言 判断有没有超时
    @DisplayName("超时断言")
    @Test
    public void testAssertTimeOut(){
        Assertions.assertTimeout(Duration.ofMillis(1000),()-> Thread.sleep(5000));
    }
    // 快速失败
    @DisplayName("快速失败")
    @Test
    public void testFail(){
        if(true){
            Assertions.fail("测试 失败");
        }
    }
}

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

package com.msb;
import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.Assumptions;
import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.Test;
import org.springframework.boot.test.context.SpringBootTest;
import java.time.Duration;
@SpringBootTest
@DisplayName("Junit5测试前置条件")
class SpringbootMybatisplusApplicationTests4 {
    @DisplayName("测试前提条件")
    @Test
    public void testAssumptions(){
        // 假设为true,才会执行
        Assumptions.assumeTrue(false,"结果不是true");
        System.out.println("后面的测试代码前提条件");
    }
    @DisplayName("简单断言1")
    @Test
    public void testAssertions1(){
        int add =10;
        Assertions.assertEquals(6,add,"add结果计算错误");
        System.out.println("后面的测试代码简单断言");
    }
}

嵌套测试
 

package com.msb;
import org.junit.jupiter.api.*;
import static org.junit.jupiter.api.Assertions.*;
import java.util.EmptyStackException;
import java.util.Stack;
@DisplayName("嵌套测试")
class SpringbootMybatisplusApplicationTests5 {
    Stack<Object> stack;
    @Test
    @DisplayName("is instantiated with new Stack()")
    void isInstantiatedWithNew() {
        new Stack<>();
        // 外层的测试不能驱动内层的测试方法
        assertNull(stack);
    }
    @Nested
    @DisplayName("when new")
    class WhenNew {
        @BeforeEach
        void createNewStack() {
            stack = new Stack<>();
        }
        @Test
        @DisplayName("is empty")
        void isEmpty() {
            assertTrue(stack.isEmpty());
        }
        @Test
        @DisplayName("throws EmptyStackException when popped")
        void throwsExceptionWhenPopped() {
            assertThrows(EmptyStackException.class, stack::pop);
        }
        @Test
        @DisplayName("throws EmptyStackException when peeked")
        void throwsExceptionWhenPeeked() {
            assertThrows(EmptyStackException.class, stack::peek);
        }
        @Nested
        @DisplayName("after pushing an element")
        class AfterPushing {
            String anElement = "an element";
            @BeforeEach // 内层Test可以驱动外层的BeforeEach
            void pushAnElement() {
                stack.push(anElement);
            }
            @Test
            @DisplayName("it is no longer empty")
            void isNotEmpty() {
                assertFalse(stack.isEmpty());
            }
            @Test
            @DisplayName("returns the element when popped and is empty")
            void returnElementWhenPopped() {
                assertEquals(anElement, stack.pop());
                assertTrue(stack.isEmpty());
            }
            @Test
            @DisplayName("returns the element when peeked but remains not empty")
            void returnElementWhenPeeked() {
                assertEquals(anElement, stack.peek());
                assertFalse(stack.isEmpty());
            }
        }
    }
}

参数化测试

package com.msb;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.Nested;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.params.ParameterizedTest;
import org.junit.jupiter.params.provider.MethodSource;
import org.junit.jupiter.params.provider.ValueSource;
import java.util.EmptyStackException;
import java.util.Stack;
import java.util.stream.Stream;
import static org.junit.jupiter.api.Assertions.*;
@DisplayName("参数化测试")
class SpringbootMybatisplusApplicationTests6 {
    @ParameterizedTest
    @ValueSource(ints = { 1, 2, 3 })
    void testWithValueSource(int argument) {
        System.out.println(argument);
        assertTrue(argument > 0 && argument < 4);
    }
    @ParameterizedTest
    @MethodSource("stringProvider")
    void testWithExplicitLocalMethodSource(String argument) {
        assertNotNull(argument);
    }
    static Stream<String> stringProvider() {
        return Stream.of("apple", "banana");
    }
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值