• 【springboot单元测试,集成测试】


    本文介绍一下SpringBoot中的测试方法

    集成测试

    @SpringBootTest

    一个普通的web api

    @RequestMapping
    @RestController
    public class HelloController {
    
        @Autowired
        RestTemplate restTemplate;
    
        @GetMapping(value = "/api/hi")
        public Map<String,Object> hello() {
    
            String baiduRes = restTemplate.getForObject("https://www.baidu.com", String.class);
            Map<String, Object> res = new HashMap<>();
            res.put("status", "中");
            res.put("msg", baiduRes);
            return res;
        }
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18

    测试类:

    
    package xyz.bliu.sptest;
    
    
    import org.junit.jupiter.api.Test;
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.boot.test.context.SpringBootTest;
    import org.springframework.test.web.servlet.MockMvc;
    import org.springframework.web.client.RestTemplate;
    
    import static org.assertj.core.api.Assertions.assertThat;
    import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get;
    import static org.springframework.test.web.servlet.result.MockMvcResultHandlers.print;
    import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;
    
    @SpringBootTest
    public class ControllerTest02 {
    
        @Autowired
        RestTemplate restTemplate;
    
        @Autowired
        MockMvc mockMvc;
    
        @Test
        public void restTemplateShouldNotNull() {
            assertThat(restTemplate).isNotNull();
        }
    
        @Test
        public void testGetRequest() throws Exception {
    
            mockMvc.perform(get("/api/hi"))
                   .andExpect(status().isOk())
                   .andDo(print());
        }
    }
    
    
    • 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

    使用mockMvc好处是不会启动真实的web服务
    当然你可以使用@SpingBootTest 并且注入一个RestTemplate来做真实的请求

    假如希望仅仅测试controller层时, 可以使用另外一个注解
    @WebMvcTest
    他有一个参数可以指定测试的controller

    
    package xyz.bliu.sptest;
    
    
    import org.junit.jupiter.api.Test;
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.boot.test.autoconfigure.web.servlet.WebMvcTest;
    import org.springframework.boot.test.mock.mockito.MockBean;
    import org.springframework.test.web.servlet.MockMvc;
    import org.springframework.web.client.RestTemplate;
    import xyz.bliu.sptest.controller.HelloController;
    
    import static org.assertj.core.api.Assertions.*;
    import static org.mockito.Mockito.when;
    import static org.springframework.test.web.servlet.result.MockMvcResultHandlers.print;
    import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get;
    import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.content;
    
    @WebMvcTest(controllers = HelloController.class)
    public class ControllerTest01 {
    
    
        @Autowired
        MockMvc mockMvc;
    
        @MockBean
        RestTemplate restTemplate;
    
        @Test
        public void helloShouldOK() throws Exception {
    
            when(restTemplate.getForObject("https://www.baidu.com", String.class)).thenReturn("haha");
    
            assertThat(mockMvc).isNotNull();
            mockMvc.perform(get("/api/hi").header("kk", "v1")
                            .header("Content-Type", "application/json"))
                    .andDo(print())
                    .andExpect(content().contentType("application/json"))
                    .andExpect(content().json("{'status':'中', 'msg':'haha'}"));
        }
    
    
        @Test
        public void restTemplateShouldBeNull() {
            assertThat(restTemplate).isNull();
        }
    }
    
    
    • 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

    这样仅会加载指定的controller和一些web层的东西不会加载其他Bean
    假如这个controller中依赖其他的bean怎么办呢?
    答案是需要使用@MockBean去Mock依赖的行为

    例如我这里的处理

     @MockBean
     RestTemplate restTemplate;
    
     when(restTemplate.getForObject("https://www.baidu.com", String.class)).thenReturn("haha");
    
    • 1
    • 2
    • 3
    • 4

    其实就是说当调用restTemplate.getForObject(“https://www.baidu.com”, String.class)时,方法会返回“haha”


    @WebMvcTest VS @SpringBootTest

    显然当你只需要测试你的controller接收请求参数或者返回值时你可以使用@WebMvcTest, 因为它不需要加载整个application context, 因此会使你的test更快

    然而当需要集成测试时则需要@SpringBootTest
    并且他们是不能同时使用的

    • 另外你可能注意到了AssertJ 提供的 assertThat api非常好用,可以流式调用

    • 另外本文测试环境为spring boot 3.x 和 Junit5
      如果你使用是springboot 2.x 你可能还需要 @RunWith(SpringRuner.class) ( junit4)或者 @extendwith(springextension.class) (junit5)

    当然你可以使用@SpingBootTest 并且注入一个RestTemplate来做真实的请求

    package xyz.bliu.sptest;
    
    import org.junit.jupiter.api.Test;
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.boot.test.context.SpringBootTest;
    import org.springframework.boot.test.web.server.LocalServerPort;
    import org.springframework.web.client.RestTemplate;
    
    import java.util.Map;
    
    import static org.assertj.core.api.Assertions.assertThat;
    
    @SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)
    public class ControllerTest03 {
    
    
        @Autowired
        RestTemplate restTemplate;
    
        @LocalServerPort
        int port;
    
        @Test
        public void testGet() {
            Map resp = restTemplate.getForObject("http://localhost:"+port+ "/api/hi", Map.class);
            assertThat(resp.get("status").toString()).isEqualTo("中");
        }
    }
    
    
    • 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
  • 相关阅读:
    Excel 数据透视表教程大全之 04 按日期分组(教程含样本数据)
    oracle数据同步报错请确认数据库名是否正确
    计算机操作系统 第五章 虚拟存储器(3)
    mysql索引详解
    基于ssm的校园快递物流管理系统(java+jsp+ssm+javabean+mysql+tomcat)
    RocketMQ源码分析(十)之MappedFileQueue
    30秒让你弄懂pdf怎么翻译,还在犹豫什么
    R语言——朴素贝叶斯文本分类
    Python吴恩达深度学习作业3 - 1层隐藏层的神经网络
    记一次hook mac地址实现伪装硬件码
  • 原文地址:https://blog.csdn.net/lsk_shah/article/details/134045052