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.引用

相关推荐
EatFan18 小时前
Spring Boot 4 迁移避坑清单:Jackson 3、starter 拆分与最低 JDK 口径核对(含若依/芋道/CRMEB 升级对照)
java·数据库·spring boot·spring boot 4·java 21·jakarta ee 11·jackson 3
ly768918 小时前
Spring Boot 集成 Redis 企业级实践:连接池、序列化与缓存穿透雪崩的工程化防御
spring boot·redis·缓存·缓存穿透·布隆过滤器·lettuce 连接池
Wx-bishekaifayuan18 小时前
springboot陨石鉴收系统96265-计算机课程设计、毕业设计
java·vue.js·spring boot·后端·python·spring·课程设计
谷哥的小弟19 小时前
网络连接测试命令Test-NetConnection
测试·ip·端口·网络连接
七夜zippoe19 小时前
Agent 自动化测试:怎么给“会自己决策“的程序写测试
ai·自动化·agent·测试·openclaw
code_slave(码畜)19 小时前
微服务架构落地:基础服务 —— 报表服务(上篇:定位、边界与整体架构)
java·spring boot·spring cloud·微服务·架构
FYKJ_201019 小时前
springboot家政服务平台66766-计算机课程设计、毕业设计
java·vue.js·spring boot·后端·mysql·spark·课程设计
x-Achan20 小时前
Redis实现方案:更新策略、穿透、雪崩、击穿、工具封装
java·spring boot·redis·spring·bootstrap·mybatis
新思维软件1 天前
非机动车管理系统设计 | STM32+RFID+MQTT | X504291项目编号 X504291
spring boot·stm32·单片机·嵌入式硬件
ym hyd 1111 天前
试题库管理系统源码 Java+SpringBoot+Vue3 前后分离
java·vue.js·spring boot·毕设