springboot 单元测试实践1

1,297 阅读3分钟

本文重点将讲述如何在单元测试中,mock controller的请求,测试controller请求,同时顺带着讲解如何在单测中测试代码日志中输出的内容。

首先,新建spring boot的项目

image.png

image.png

image.png

image.png

按照上面几张图的操作,一个简单的spring boot 项目就建立好了

上图中,我建立了一个gradle管理spring boot项目,项目的结构如下图,左侧图示。

这里要额外说一下,有gradlew / gradlew.bat的脚本,mac 或者 linux系统可以在项目的当前目录下,执行 ./gradlew build 来构建整个项目,Windows使用gradlew.bat的脚本或者在Windows的bash下同样执行 ./gradlew build 来构建整个项目

image.png

上图中,标红的部分,是一种代码风格规范约束,代码的缩进换行,统一使用 google java format。

比如,不同的人,可能使用不同的操作系统进行编程,哪怕是使用同样的操作系统,但是每个人的idea的配置都是有差异的,再加上每个人的代码风格习惯不一样,就很难在一个项目形成统一的风格,所以在项目中配置了上述的 google java format, 每个人在提交代码前执行 ./gradlew spotlessApply, 这样整个工程就按照统一的编码风格来规范代码了。

我把上面的配置贴在了下面,方便读者 ctrl + c / ctrl + v

id "com.diffplug.gradle.spotless" version "3.27.1"


spotless {
    java {
        target project.fileTree(project.rootDir) {
            include '**/*.java'
        }
        googleJavaFormat()
    }
}

打开工程中生成DemoApplication这个spring boot main的主入口文件在上面加入exclude, 排除掉spring security

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

@SpringBootApplication(
    exclude = {
      org.springframework.boot.autoconfigure.security.servlet.SecurityAutoConfiguration.class
    })
public class DemoApplication {

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

创建 DemoConfiguration类

import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;

@Configuration
@ComponentScan({"com.example.demo"})
@EnableAutoConfiguration
public class DemoConfiguration implements WebMvcConfigurer {}

spring boot 扫描包的默认规则是扫描和DemoApplication同一目录下的所有内容,因为后续,我们会创建子目录放置controller 、service等bean,所以在DemoConfiguration上指定包扫描了 com.example.demo下所有的文件,参考如下图

image.png

创建controller文件夹,在文件夹下新建一个DemoController类

package com.example.demo.controller;

import lombok.extern.slf4j.Slf4j;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

@RestController
@RequestMapping("/api")
@Slf4j
public class DemoController {

  @GetMapping("/log")
  public String log() {
    log.info("test print log");
    return "log";
  }
}

在这个Controller中,新建了一个http get请求的接口/api/log,实现内打印 test print log这句话

截止到这里,我们新建了一个spring boot项目,并且创建了一个DemoController,对外提供了get方法的/api/log接口。

打开DemoController,mac下快捷键使用 cmd + shift + T, 快速的创建单测类 DemoControllerTest,代码如下

package com.example.demo.controller;

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

import com.example.demo.extensions.CaptureSystemOutput;
import javax.validation.constraints.NotNull;
import org.junit.jupiter.api.Test;
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.test.web.servlet.MockMvc;
import org.springframework.test.web.servlet.request.MockMvcRequestBuilders;
import org.springframework.test.web.servlet.result.MockMvcResultMatchers;

@SpringBootTest
@AutoConfigureMockMvc
@CaptureSystemOutput
class DemoControllerTest {

  @Autowired private MockMvc mockMvc;

  @Test
  void log(@NotNull CaptureSystemOutput.OutputCapture outputCapture) throws Exception {
    this.mockMvc
        .perform(
            MockMvcRequestBuilders.get("/api/log").header("key", "value").param("key", "value"))
        .andExpect(MockMvcResultMatchers.status().isOk());

    assertTrue(outputCapture.toString().contains("test print log"));
  }
}

我们使用spring boot内置的mockMvc来模拟浏览器请求,指定get方法的/api/log接口,这里为了演示如何模拟header和请求参数的构造,分别写了.header() .param()来模拟header和请求参数的构造

之后,我们校验的是期望接口返回是200,也就是上图中的 andExpect后的 status.isOk()的单测校验

这里,我加入了一个开源的CaptureSystemOutput的类,参考地址github.com/sbrannen/ju…

这个类的主要用法,就是校验控制台日志输出的内容,是否是我们代码中的期望输出。

这个,也就是如何在单测中,来测试业务代码中,log日志是否正常输出打印。