Spring Boot单元测试快速入门Demo

1.test介绍

软件测试是一个应用软件质量的保证。开发者开发接口往往忽视接口单元测试。如果会Mock单元测试,那么你的bug量将会大大降低。spring提供test测试模块。整体上,Spring Boot Test支持的测试种类,大致可以分为如下三类:

  • 单元测试:一般面向方法,编写一般业务代码时,测试成本较大。涉及到的注解有@Test。
  • 切片测试:一般面向难于测试的边界功能,介于单元测试和功能测试之间。涉及到的注解有@RunWith @WebMvcTest等。
  • 功能测试:一般面向某个完整的业务功能,同时也可以使用切面测试中的mock能力,推荐使用。涉及到的注解有@RunWith @SpringBootTest等。

功能测试过程中的几个关键要素及支撑方式如下:

  • 测试运行环境:通过@RunWith 和 @SpringBootTest启动spring容器。
  • mock能力:Mockito提供了强大mock功能。
  • 断言能力:AssertJ、Hamcrest、JsonPath提供了强大的断言能力。

2.代码工程

实验目的:验证cotroller和service层逻辑

pom.xml

xml 复制代码
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <parent>
        <artifactId>springboot-demo</artifactId>
        <groupId>com.et</groupId>
        <version>1.0-SNAPSHOT</version>
    </parent>
    <modelVersion>4.0.0</modelVersion>

    <artifactId>test</artifactId>

    <properties>
        <maven.compiler.source>8</maven.compiler.source>
        <maven.compiler.target>8</maven.compiler.target>
    </properties>
    <dependencies>

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

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

    </dependencies>
</project>

配置文件

yaml 复制代码
server:
  port: 8088
  username: default

server:
  port: 8088
  username: dev

cotroller

typescript 复制代码
package com.et.test.controller;

import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;

import java.util.HashMap;
import java.util.Map;

@Controller
public class HelloWorldController {
    @RequestMapping("/hello")
    @ResponseBody
    public Map<String, Object> showHelloWorld(){
        Map<String, Object> map = new HashMap<>();
        map.put("msg", "HelloWorld");
        return map;
    }
}

service

kotlin 复制代码
package com.et.test.service;

import org.springframework.stereotype.Service;

/**
 * @ClassName UserService
 * @Description TODO
 * @Author liuhaihua
 * @Date 2024/4/4 13:13
 * @Version 1.0
 */
public interface UserService {
   public   String getUserName();
}

package com.et.test.service;

import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;

/**
 * @ClassName UserServiceImpl
 * @Description TODO
 * @Author liuhaihua
 * @Date 2024/4/4 13:16
 * @Version 1.0
 */
@Service
public class UserServiceImpl implements UserService{
   @Value("${server.username}")
   private String username;
   @Override
   public String getUserName() {
      return username;
   }
}

DemoApplication.java

typescript 复制代码
package com.et.test;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;

@SpringBootApplication
public class DemoApplication {

   public static void main(String[] args) {
      SpringApplication.run(DemoApplication.class, args);
   }
}

以上只是一些关键代码,所有代码请参见下面代码仓库

代码仓库

3.测试

验证环境绑定

kotlin 复制代码
@ActiveProfiles("dev")

可以切换不同的环境,在同的环境上测试

验证controller功能

scss 复制代码
@Test
public void bookApiTest() throws Exception {

   // mockbean start
   userServiceMockBean();
   // mockbean end
   String expect = "{\"msg\":\"HelloWorld\"}";
   mockMvc.perform(MockMvcRequestBuilders.get("/hello"))
         .andExpect(MockMvcResultMatchers.content().json(expect))
         .andDo(MockMvcResultHandlers.print());
   // mockbean reset
}

验证service功能

csharp 复制代码
  @Test
  public void execute() {
      userServiceMockBean();
      log.info("username:"+userService.getUserName());
      Assertions.assertThat(userService.getUserName().equals("mockname"));

  }

下面是完整的测试代码,感兴趣的可以去测试一下

java 复制代码
package com.et.test;

import com.et.test.service.UserService;
import org.assertj.core.api.Assertions;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.BDDMockito;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureMockMvc;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.boot.test.mock.mockito.MockBean;
import org.springframework.test.context.ActiveProfiles;
import org.springframework.test.context.junit4.SpringRunner;
import org.springframework.test.web.servlet.MockMvc;
import org.springframework.test.web.servlet.request.MockMvcRequestBuilders;
import org.springframework.test.web.servlet.result.MockMvcResultHandlers;
import org.springframework.test.web.servlet.result.MockMvcResultMatchers;

import javax.annotation.Resource;


@RunWith(SpringRunner.class)
@SpringBootTest(classes = DemoApplication.class)
@ActiveProfiles("dev")
@AutoConfigureMockMvc
public class DemoTests {
    private Logger log = LoggerFactory.getLogger(getClass());
   @Resource
   private MockMvc mockMvc;
   //@Autowired
   @MockBean
   UserService userService;
    @Before
    public void before()  {
        log.info("init some data");
    }
    @After
    public void after(){
        log.info("clean some data");
    }
    @Test
    public void execute() {
      userServiceMockBean();
        log.info("username:"+userService.getUserName());
      Assertions.assertThat(userService.getUserName().equals("mockname"));

    }
   @Test
   public void bookApiTest() throws Exception {

      // mockbean start
      userServiceMockBean();
      // mockbean end
      String expect = "{\"msg\":\"HelloWorld\"}";
      mockMvc.perform(MockMvcRequestBuilders.get("/hello"))
            .andExpect(MockMvcResultMatchers.content().json(expect))
            .andDo(MockMvcResultHandlers.print());
      // mockbean reset
   }

   public void userServiceMockBean() {
      BDDMockito.given(userService.getUserName()).willReturn("mockname");
   }

}

4.引用

相关推荐
尚学教辅学习资料2 小时前
Ruoyi-vue-plus-5.x第五篇Spring框架核心技术:5.1 Spring Boot自动配置
vue.js·spring boot·spring
晚安里2 小时前
Spring 框架(IoC、AOP、Spring Boot) 的必会知识点汇总
java·spring boot·spring
上官浩仁3 小时前
springboot ioc 控制反转入门与实战
java·spring boot·spring
叫我阿柒啊3 小时前
从Java全栈到前端框架:一位程序员的实战之路
java·spring boot·微服务·消息队列·vue3·前端开发·后端开发
中国胖子风清扬4 小时前
Rust 序列化技术全解析:从基础到实战
开发语言·c++·spring boot·vscode·后端·中间件·rust
JosieBook8 小时前
【SpringBoot】21-Spring Boot中Web页面抽取公共页面的完整实践
前端·spring boot·python
刘一说8 小时前
Spring Boot+Nacos+MySQL微服务问题排查指南
spring boot·mysql·微服务
叫我阿柒啊12 小时前
从Java全栈到云原生:一场技术深度对话
java·spring boot·docker·微服务·typescript·消息队列·vue3
计算机毕设定制辅导-无忧学长12 小时前
MQTT 与 Java 框架集成:Spring Boot 实战(一)
java·网络·spring boot
叫我阿柒啊12 小时前
从Java全栈到Vue3实战:一次真实面试的深度复盘
java·spring boot·微服务·vue3·响应式编程·前后端分离·restful api