springboot单元测试JUnit5、断言

1 简介

在Spring Boot2.4之后就不兼容JUnit4及以前的版本了

2 JUnit5依赖

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

3 注意事项

写测试类,包名要和非测试类包名一致

4 常用注解

  1. @SpringBootTest @Test
@SpringBootTest
public class JUnit5Test {

    @DisplayName("测试 @DisplayName()")
    @Test
    void testDisplayName(){
        System.out.println("这是 @DisplayName()的测试!");
    }
}

@Autowired自动装配注入
@Transactional标注测试方法,测试结束进行回滚
@Test 用于声明该方法是测试方法
@ParameterizedTest 参数化测试

  1. @RepeatedTest()
    对测试方法进行重复测试
    @RepeatedTest(value = 2)
    @DisplayName("测试 @DisplayName()")
    @Test
    void testDisplayName(){
        System.out.println("这是 @DisplayName()的测试!");
    }
  1. @DisplayName() 用于指定测试方法或测试类的展示名称
@SpringBootTest
public class JUnit5Test {

    @DisplayName("测试 @DisplayName()")
    @Test
    void testDisplayName(){
        System.out.println("这是 @DisplayName()的测试!");
    }
}
  1. @BeforeEach
    用于在每个测试方法之前进行操作
    @BeforeEach
    void testBeforeEach(){
        System.out.println("测试即将开始--->");
    }
  1. @BeforeAll
    用于在所有测试方法之前进行操作
 @BeforeAll
    static void testBeforeAll(){
        System.out.println("**********测试开始**********");
 }
  1. @AfterAll
    用于在所有测试方法之后进行操作
@AfterAll
    static void testAfterAll(){
        System.out.println("***********测试结束**********");
    }
  1. @AfterEach
    用于在每个测试方法之后进行操作
@AfterEach
    void testAfterEach(){
        System.out.println("测试结束--->");
    }
  1. @Tag()
    用于表示单元测试类别

  2. @Disabled
    用于取消测试方法或测试类(不执行)

    @Disabled
    @DisplayName("测试2")
    @Test
    void testDisplayName2(){
        System.out.println("这是 @DisplayName()的第二个测试!");
    }
  1. @Timeout()
    用于设定测试方法若超出规定事件就会返回错误
    @DisplayName("TimeOut的测试方法")
    @Timeout(value = 5,unit = TimeUnit.MILLISECONDS)
    @Test
    void testTimeOut(){
        try {
            Thread.sleep(20);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        System.out.println("@TimeOut 的测试");
    }
  1. @ExtendWith()
    用于为测试类或测试方法提供扩展类引用
    我们看到SpringBoot里使用的@SpringBootTest注解就有这个

完整常用注解测试类

import org.junit.jupiter.api.*;
import org.springframework.boot.test.context.SpringBootTest;

import java.util.concurrent.TimeUnit;

@SpringBootTest
public class JUnit5Test {

    @DisplayName("TimeOut的测试方法")
    @Timeout(value = 5,unit = TimeUnit.MILLISECONDS)
    @Test
    void testTimeOut(){
        try {
            Thread.sleep(20);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        System.out.println("@TimeOut 的测试");
    }

    @RepeatedTest(value = 2)
    @DisplayName("测试 @DisplayName()")
    @Test
    void testDisplayName(){
        System.out.println("这是 @DisplayName()的测试!");
    }

    @Disabled
    @DisplayName("测试2")
    @Test
    void testDisplayName2(){
        System.out.println("这是 @DisplayName()的第二个测试!");
    }

    @BeforeEach
    void testBeforeEach(){
        System.out.println("测试即将开始--->");
    }

    @AfterEach
    void testAfterEach(){
        System.out.println("测试结束--->");
    }

    @BeforeAll
    static void testBeforeAll(){
        System.out.println("**********测试开始**********");
    }

    @AfterAll
    static void testAfterAll(){
        System.out.println("***********测试结束**********");
    }
}

5 断言机制

用于对测试需要满足的条件进行验证(检测业务逻辑返回的数据是否合理)
断言方法都在junit.jupiter.api.Assertions的静态方法中
当测试出现问题之后会给测试者一个详细的测试报告
断言情况下前面断言出现问题后面则不会执行

5.1 简单断言

assertEquals()方法
用于判断传入的两个对象原始类型是否相同

public static void assertEquals(int expected, int actual, String message) {
AssertEquals.assertEquals(expected, actual, message);
}

第三个参数是可以用来设置测试失败后自定义的信息打印

assertEquals(judgeNum,10,“测试结果错误”);

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.util.Scanner;

import static org.junit.jupiter.api.Assertions.*;

@SpringBootTest
public class JUnit5AssertionTest {

    @DisplayName("简单断言测试")
    @Test
    void simpleAssertionTest(){
        int judgeNum = judge(2, 5);
        assertEquals(judgeNum,10);
    }

    int judge(int num1,int num2){
        int num = num1>num2?num1:num2;
        return num;
    }
}

assertSame()方法
用于判断两个对象是否是同一个对象

@DisplayName(" assertSame 断言测试")
    @Test
    void assertSameTest(){
        Object obj1 = new Object();
        Object obj2 = new Object();
        assertSame(obj1,obj2,"测试失败");
    }

assertNotEquals()判断两个对象的原始类型是否不同
assertNotSame()判断两个对象是否不是同一个对象
assertTrue()判断给定的布尔值是否为True
assertFalse()判断给定的布尔值是否为false
assertNull()判断给定的对象引用是否为 NULL
assertNotNull()判断给定的对象引用是否不为Null

5.2 数组断言

assertArrayEquals()
判断两个数组中的值是否相同
传入的两个数组一定要是同一个类型的

@Test
void assertArray() {
    assertArrayEquals(new int[]{1, 6}, new int[]{6, 1}, "测试失败");
}

5.3 组合断言

assertAll()
assertAll方法可以通过lambda表达式进行判断

@Test
void assertAllTest(){
    assertAll("test",
            ()-> assertArrayEquals(new double[]{1.5,8},new double[]{1,8}),
            ()-> assertNotSame(8,8));
}

5.4 异常断言

assertThrows()
断定业务逻辑一定出现异常

@DisplayName("异常断言")
@Test
void assertThrowsTest(){
    assertThrows(Exception.class,()->{int i = 1/0;},"异常未出现");
}

5.5 超时断言

assertTimeout()
断定在设置的时间里一定会成功超时则出现异常

@DisplayName(“超时断言”)
@Test
void timeOutTest(){
assertTimeout(Duration.ofSeconds(1),()->{Thread.sleep(800);});
}

5.6 快速失败

fail()
通过使用fail方法直接让测试失败

@Test
void failTest(){
    fail("我直接失败怎么说?");
}

5.7 前置条件

assumptions
类似于断言,其实就是测试方法执行的前提条件若不满足则无法测试

区别
若不满足前置条件则测试终止而非失败

    @DisplayName("前置条件的测试")
@Test
void assumptionTest(){
    Assumptions.assumeTrue(false,"前提不是true");
    System.out.println("方法执行成功");
}

5.8 嵌套测试

Nested Tests
文档
https://junit.org/junit5/docs/current/user-guide/#writing-tests-nested

@Nested 测试为测试编写者提供了更多的能力来表达多组测试之间的关系。这种嵌套测试使用Java的嵌套类,并促进了对测试结构的分层思考。

注意点
当我们要写嵌套测试的时候要在书写嵌套测试的“大”方法上添加注释@Nested
嵌套测试的情况下,外层的Test无法驱动内层
@Nested
class Outter{
@Test
void test1(){

}
@Test
void test2(){

}
@Test
void test3(){

}
}

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 java.util.EmptyStackException;
import java.util.Stack;

import static org.junit.jupiter.api.Assertions.*;

@DisplayName("嵌套测试")
public class NestedTestDemo {
    Stack<Object> stack;

    @Test
    @DisplayName("is instantiated with new Stack()")
    void isInstantiatedWithNew() {
        new 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
            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());
            }
        }
    }
}

5.9 参数化测试

能够使用不同的参数进行多次运行测试
使用注解指定入参
它们的声明方式与常规的 @Test 方法一样,但使用 @ParameterizedTest 注释

文档
https://junit.org/junit5/docs/current/user-guide/#writing-tests-parameterized-tests

参数化测试常用注解

  1. @ValueSource
    指定入参来源

  2. @NullSource
    提供一个Null入参

  3. @EnumSource
    提供一个枚举入参

  4. CsvFileSource
    提供一个csv文件内容作为参数入参

  5. MethodSource
    读取指定方法的返回值作为参数化测试的入参(流)

import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.params.ParameterizedTest;
import org.junit.jupiter.params.provider.EmptySource;
import org.junit.jupiter.params.provider.EnumSource;
import org.junit.jupiter.params.provider.NullSource;
import org.junit.jupiter.params.provider.ValueSource;
import org.junit.platform.commons.util.StringUtils;


import java.time.temporal.ChronoUnit;
import java.time.temporal.TemporalUnit;

import static org.junit.jupiter.api.Assertions.assertNotNull;
import static org.junit.jupiter.api.Assertions.assertTrue;

@DisplayName("参数化测试")
public class ParamTestDemo {

    @ParameterizedTest
    @ValueSource(ints = { 1, 2, 3 })
    void testWithValueSource(int argument) {
        assertTrue(argument > 0 && argument < 4);
    }
    
    @ParameterizedTest
    @ValueSource(strings = { "racecar", "radar", "able was I ere I saw elba" })
    void palindromes(String candidate) {
        System.out.println(candidate);
    }

    @ParameterizedTest
    @NullSource
    @EmptySource
    @ValueSource(strings = { " ", "   ", "\t", "\n" })
    void nullEmptyAndBlankStrings(String text) {
        assertTrue(text == null || text.trim().isEmpty());
    }

    @ParameterizedTest
    @EnumSource(ChronoUnit.class)
    void testWithEnumSource(TemporalUnit unit) {
        assertNotNull(unit);
    }
}
  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值