• 单元测试-学习笔记


    前言

    关于单元测试的内容暂时也是在学习中,记录一下单元测试的用法,提供参考,只提供了些核心代码。

    一、涉及的依赖

            <dependency>
                <groupId>org.springframework.bootgroupId>
                <artifactId>spring-boot-starter-webartifactId>
            dependency>
            <dependency>
                <groupId>org.springframework.bootgroupId>
                <artifactId>spring-boot-starter-testartifactId>
                <scope>testscope>
            dependency>
            <dependency>
                <groupId>org.projectlombokgroupId>
                <artifactId>lombokartifactId>
                <optional>trueoptional>
            dependency>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14

    二、注解说明和案例演示

    标识说明
    @BeforeAll@BeforeAll 带注释的方法必须是测试类中的静态方法。在执行@Test之前会优先执行这个方法,并且只执行一次
    @BeforeEach@BeforeEach 带注释的方法不能是静态方法,否则会抛出运行时错误。在执行@Test之前会优先执行这个方法并且每次执行都会执行@BeforeEach修饰的方法
    @MockBean模拟一个Bean,是个壳子Bean,其行为和返回值可以用 Mockito.when(XXX).then(XXX)进行预设模拟
    @DisplayName()执行时右侧名称展示,具体后面有图标明,可以配合@RepeatedTest()注解使用
    @RepeatedTest(5)重复执行5次

    样例``

    package com.example.unit.test.demo.service.impl;
    
    import com.example.unit.test.demo.api.OtherService;
    import com.example.unit.test.demo.controller.domain.Calculator;
    import lombok.extern.slf4j.Slf4j;
    import org.junit.jupiter.api.*;
    import org.springframework.boot.test.context.SpringBootTest;
    import org.springframework.boot.test.mock.mockito.MockBean;
    
    /**
     * @author 起凤
     * @description: TODO
     * @date 2022/7/6
     */
    @Slf4j
    @SpringBootTest
    public class BeforeEachTest {
    
        @MockBean
        private OtherService otherService;
    
        // BeforeAll 每个方法执行时,repeated时只会调用一次
        @BeforeAll
        public static void init() {
            log.warn("BeforeAll Method init() method called");
        }
    
        // BeforeEach 每个方法执行时,repeated时只会调用多次
        @BeforeEach
        public void initEach() {
            log.error("BeforeEach initEach() method called");
        }
    
       // DisplayName 执行时展示板上加个别名,看图
        @DisplayName("Add operation test")
        @RepeatedTest(5)
        void addNumber(TestInfo testInfo, RepetitionInfo repetitionInfo) {
            System.out.println("Running Test  ->" + repetitionInfo.getCurrentRepetition());
            Assertions.assertEquals(2, Calculator.add(1, 1), "1 + 1 should equal 2");
        }
    
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42

    执行时能看到 @BeforeAll 最早执行,且只执行一次, @BeforeEach每次重复都执行且先于重复体执行,@RepeatedTest(5) 标识后会执行5次,@DisplayName("Add operation test") 标识后重复执行里的左侧绿色的勾勾下的名称就叫Add operation test

    在这里插入图片描述

    样例DemoServiceTest.java

    package com.example.unit.test.demo.service.impl;
    
    import com.example.unit.test.demo.api.OtherService;
    import com.example.unit.test.demo.controller.domain.EchoRequest;
    import com.example.unit.test.demo.controller.domain.EchoResponse;
    import com.example.unit.test.demo.service.IDemoService;
    import com.example.unit.test.demo.utils.SessionUtils;
    import org.junit.jupiter.api.Assertions;
    import org.junit.jupiter.api.BeforeAll;
    import org.junit.jupiter.api.BeforeEach;
    import org.junit.jupiter.api.Test;
    import org.mockito.Mockito;
    import org.mockito.stubbing.Answer;
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.boot.test.context.SpringBootTest;
    import org.springframework.boot.test.mock.mockito.MockBean;
    
    import java.util.UUID;
    
    import static org.junit.jupiter.api.Assertions.*;
    
    /**
     * @author 起凤
     * @description: TODO
     * @date 2022/7/6
     */
    @SpringBootTest
    class DemoServiceTest {
    
        // 模拟外部调用需要进行Mock
        @MockBean
        private SessionUtils sessionUtils;
        @MockBean
        private OtherService otherService;
        @Autowired
        private IDemoService demoService;
    
        // @BeforeAll 带注释的方法必须是测试类中的静态方法。
        // 在执行@Test之前会优先执行这个方法
        @BeforeAll
        public static void beforeAll() {
            System.out.println("BeforeAll init() method called");
        }
    
        // @BeforeEach 带注释的方法不能是静态方法,否则会抛出运行时错误。
        // 对外请求和线程上下文相关行为进行Mock
        @BeforeEach
        public void beforeEach() {
            // 进行提前mock 相当于当 sessionUtils.getCurrentUser() 被调用时就会返回 hello
            Mockito.when(sessionUtils.getCurrentUser()).thenReturn("hello");
            // 进行提前mock 相当于当 otherService.doSomething() 被调用时就会返回该入参时候的第0个参数
            // 可以 Mockito.anyXXXX, 具体进入看源码,对请求入参的参数mock
            Mockito.when(otherService.doSomething(Mockito.anyString()))
                    .thenAnswer((Answer<String>) invocationOnMock -> invocationOnMock.getArgument(0));
        }
    
        // 使用随机输入测试 Echo,这里demoService的echo方法内部有调用 OtherService的doSomething方法
        // OtherService 已经被@MockBean修饰,且该方法提前在@BeforeEache里预设mock调用是是返回第一个入参
        @Test
        public void testEchoWithRandomInput() {
            String input = UUID.randomUUID().toString();
            EchoResponse resp = demoService.echo(EchoRequest.builder()
                    .input(input).build());
    
            // 这里 resp.getOutput() == input正常不会抛出异常
            Assertions.assertEquals(resp.getOutput(), input);
            // 这里不一致会抛异常 resp.getOutput() 返回的是input 是一个UUID值
            Assertions.assertEquals(resp.getOutput(), "1234");
    
        }
    
        @Test
        void testSessionUtils() {
            String currentUser = sessionUtils.getCurrentUser();
            /// 下面这行打开会报错 前面设置了 sessionUtils调用getCurrentUser时返回 hello
            // Assertions.assertEquals(currentUser,"hello1");
            Assertions.assertEquals(currentUser, "hello");
    
            String aaa = otherService.doSomething("aaa");
            Assertions.assertEquals(aaa, "aaa1");
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79
    • 80
    • 81
    • 82

    样例 IDemoService.java

    package com.example.unit.test.demo.service.impl;
    
    import com.example.unit.test.demo.api.OtherService;
    import com.example.unit.test.demo.controller.domain.EchoRequest;
    import com.example.unit.test.demo.controller.domain.EchoResponse;
    import com.example.unit.test.demo.service.IDemoService;
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.stereotype.Component;
    
    /**
     * @author 起凤
     * @description: TODO
     * @date 2022/7/6
     */
    @Component
    public class DemoService implements IDemoService {
    
        @Autowired
        private OtherService otherService;
    
        @Override
        public EchoResponse echo(EchoRequest request) {
            return EchoResponse.builder()
                    .output(otherService.doSomething(request.getInput()))
                    .build();
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27

    参考资料

  • 相关阅读:
    小白论文写作心得
    HTML+CSS大作业:使用html设计一个简单好看的公司官网首页 浮动布局
    C++设计模式_13_Flyweight享元模式
    观察者模式java
    linux c++ 学习记录
    Linux权限
    探索Manticore Search:开源全文搜索引擎的强大功能
    【Vue指令】五分钟了解vue的数据绑定
    视频监控系统EasyCVR如何通过API接口获取国标GB28181协议接入的实时录像?
    一份企业业务流程自动化指南
  • 原文地址:https://blog.csdn.net/LvQiFen/article/details/126432936