springboot企业级项目开发之项目测试——集成测试!

集成测试

集成测试是指项目代码在单元测试完成后进行的第二阶段测试。集成测试的重点是在集成组件或单元之间交互时暴露缺陷,以保证不同模块之间相互调用的正确性。在Spring Boot的项目集成测试中,将测试Controller和Dao的完整请求处理。应用程序在服务器中运行,以创建应用程序上下文和所有的Bean,其中有些Bean可能会被覆盖以模拟某些行为。进行集成测试,是为了保证项目能够达到下面的目的:

降低项目中发生错误的风险;

验证接口的功能是否符合设计的初衷;

测试接口是否可用;

查找项目中的Bug并进行修复。

在项目开发中,需要开展集成测试的情况有以下4种:

单个模块由开发人员设计,而多个模块之间的设计可能不尽相同;

检查多个模块与数据库是否正确连通;

验证不同模块之间是否存在不兼容或错误的情况;

验证不同模块之间的异常和错误处理。

集成测试自动配置

Spring Boot框架支持集成测试,项目开发时只需要做简单的配置就可以完成集成测试。本节将在7.1节的基础上介绍项目配置后进行集成测试的过程。

首先在pom.xml中添加项目依赖:

<parent>

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

<version>2.3.10.RELEASE</version>

<relativePath/> <!-- lookup parent from repository -->

</parent>

<groupId>com.example</groupId>

<artifactId>junit5-demo</artifactId>

<version>0.0.1-SNAPSHOT</version>

<name>junit5-demo</name>

<description>Demo project for Spring Boot</description>

<properties>

<java.version>11</java.version>

</properties>

<dependencies>

<dependency>

<groupId>org.springframework.boot</groupId>

<artifactId>spring-boot-starter</artifactId>

</dependency>

<dependency>

<groupId>org.springframework.boot</groupId>

<artifactId>spring-boot-starter-web</artifactId>

</dependency>

<!--加入JUnit5进行测试;如果想用JUnit4进行测试,则把exclusions去除-->

<dependency>

<groupId>org.springframework.boot</groupId>

<artifactId>spring-boot-starter-test</artifactId>

<scope>test</scope>

</dependency>

<dependency>

<groupId>org.projectlombok</groupId>

<artifactId>lombok</artifactId>

<optional>true</optional>

</dependency>

<dependency>

<groupId>org.mockito</groupId>

<artifactId>mockito-core</artifactId>

<version>3.11.2</version>

</dependency>

</dependencies>@SpringBootTest是Spring Boot提供的一个注解,表示当前类是SpringBoot环境中的一个测试类。如果使用的是JUnit 4,则需要用到@RunWith(SpringRunner.class)和@Spring-BootTest注解。但是在JUnit 5中,只需要使用@SpringBootTest注解就可以了。

测试Spring MVC入口

下面使用Spring中的集成测试模块来测试项目入口Controller的方法。

(1)新建GoodsController类,并新建要测试的业务代码,代码如下:

package com.example.junit5demo.controller;

import com.example.junit5demo.service.GoodsService;

import org.springframework.beans.factory.annotation.Autowired;

import org.springframework.web.bind.annotation.*;

@RestController

public class GoodsController {

@Autowired

private GoodsService goodsService;

@GetMapping("/queryGood")

public String queryGood(@RequestParam("name") String name) {

goodsService.queryGood(name);

return "queryGood " + name;

}

@PostMapping("/countGood")

public String countGood(@RequestBody Goods goods) {

goodsService.countGood(goods.getName());

return "countGood " + goods;

}

}

(2)新建Goods的实体类,代码如下:

package com.example.junit5demo.controller;

import lombok.Data;

@Data

public class Goods {

private long id;

private String name;

private int status;

}

(3)新建Goods的service和实现类,代码如下:

package com.example.junit5demo.service;

public interface GoodsService {

void queryGood(String name);

void countGood(String name);

}

Goods的实现类代码如下:

package com.example.junit5demo.service;

import org.springframework.stereotype.Service;

@Service

public class GoodsServiceImpl implements GoodsService {

@Override public void queryGood(String name) {

System.out.println("执行了goods的queryGood方法,参数:" + name);

}

@Override

public void countGood(String name) {

System.out.println("执行了goods的countGood方法,参数:" + name);

}

}

(4)编写Controller的集成测试用例,代码如下:

package com.example.junit5demo.controller;

import lombok.extern.SLF4J.SLF4J;

import org.junit.jupiter.api.BeforeEach;

import org.junit.jupiter.api.Test;

import org.springframework.beans.factory.annotation.Autowired;

import org.springframework.boot.test.autoconfigure.web.servlet.Auto

ConfigureMockMvc;

import org.springframework.boot.test.context.SpringBootTest;

import org.springframework.http.MediaType;

import org.springframework.mock.web.MockHttpSession;

import org.springframework.test.web.servlet.MockMvc;

import org.springframework.test.web.servlet.MvcResult;

import

org.springframework.test.web.servlet.request.MockMvcRequestBuilders;

import

org.springframework.test.web.servlet.result.MockMvcResultHandlers;

import

org.springframework.test.web.servlet.result.MockMvcResultMatchers;

@Slf4j

@SpringBootTest

@AutoConfigureMockMvc

class GoodsControllerTest {

private MockHttpSession session; @Autowired

private MockMvc mvc;

@BeforeEach

public void setupMockMvc() {

//设置MVC

session = new MockHttpSession();

}

@Test

void queryGood() throws Exception {

MvcResult mvcResult = (MvcResult) mvc.perform(MockMvcRequest

Builders.get("/queryGood")

.accept(MediaType.ALL)

.session(session)

.param("name", "cc")

)

.andExpect(MockMvcResultMatchers.status().isOk())

.andDo(MockMvcResultHandlers.print())

.andReturn();

//得到返回代码

int status = mvcResult.getResponse().getStatus();

//得到返回结果

String result = mvcResult.getResponse().getContentAsString();

log.info("status是:{},内容是:{}", status, result);

}

@Test

void countGood() throws Exception {

String body = "{\"id\":1,\"name\":\"cc\",\"status\":2}";

MvcResult mvcResult = (MvcResult) mvc.perform(MockMvcRequest

Builders.post("/countGood")

.accept(MediaType.ALL)

.session(session)

.content(body)

.contentType(MediaType.APPLICATION_JSON)

)

.andExpect(MockMvcResultMatchers.status().isOk())

.andDo(MockMvcResultHandlers.print())

.andReturn(); //得到返回代码

int status = mvcResult.getResponse().getStatus();

//得到返回结果

String result = mvcResult.getResponse().getContentAsString();

log.info("status是:{},内容是:{}", status, result);

}

}

(5)运行第一个测试用例,在控制台上可以看到测试用例的输出结果,它执行了queryGood的GET方法,实际调用了代码中的方法,且返回了预期的结果。

执行了goods的queryGood方法,参数:cc

MockHttpServletRequest:

HTTP Method = GET

Request URI = /queryGood

Parameters = {name=[cc]}

Headers = [Accept:"*/*"]

Body = null

Session Attrs = {}

Handler:

Type = com.example.junit5demo.controller.GoodsController

Method = com.example.junit5demo.controller.GoodsController

#queryGood(String)

Async:

Async started = false

Async result = null

Resolved Exception:

Type = null

ModelAndView:

View name = null

View = null Model = null

FlashMap:

Attributes = null

MockHttpServletResponse:

Status = 200

Error message = null

Headers = [Content-Type:"text/plain;charset=UTF-8", Content

Length:"12"]

Content type = text/plain;charset=UTF-8

Body = queryGood cc

Forwarded URL = null

Redirected URL = null

Cookies = []

2021-07-10 15:51:30.786 INFO 15428 --- [ main]

c.e.j.controller.

GoodsControllerTest : status是:200,内容是:queryGood cc

2021-07-10 15:51:30.808 INFO 15428 --- [extShutdownHook]

o.s.s.concurrent.

ThreadPoolTaskExecutor : Shutting down ExecutorService 'application

TaskExecutor'

(6)执行第二个测试用例的方法,并执行countGood的POST方法,当前POST使用的是application/json方式,需要单独设置,通过日志可以看到已经请求成功。

执行了goods的countGood方法,参数:cc

MockHttpServletRequest:

HTTP Method = POST

Request URI = /countGood

Parameters = {}

Headers = [Content-Type:"application/json;charset=UTF-8",

Accept:"*/*", Content-Length:"31"]

Body = {"id":1,"name":"cc","status":2}

Session Attrs = {}Handler:

Type = com.example.junit5demo.controller.GoodsController

Method = com.example.junit5demo.controller.GoodsController#

countGood(Goods)

Async:

Async started = false

Async result = null

Resolved Exception:

Type = null

ModelAndView:

View name = null

View = null

Model = null

FlashMap:

Attributes = null

MockHttpServletResponse:

Status = 200

Error message = null

Headers = [Content-Type:"text/plain;charset=UTF-8", Content

Length:"40"]

Content type = text/plain;charset=UTF-8

Body = countGood Goods(id=1, name=cc, status=2)

Forwarded URL = null

Redirected URL = null

Cookies = []

2021-07-10 15:54:18.096 INFO 15720 --- [ main]

c.e.j.controller.

GoodsControllerTest : status是:200,内容是:countGood Goods(id=1,

name=cc, status=2)

2021-07-10 15:54:18.119 INFO 15720 --- [extShutdownHook]

o.s.s.concurrent.

ThreadPoolTaskExecutor : Shutting down ExecutorService 'application

TaskExecutor'

通过以上的集成测试,完成了API从入口开始的全链路方法调用,验证了所有的方法调用,并完成了业务代码的测试,至此完成了Controller的集成测试过程。

相关推荐
春与秋其代序2 分钟前
微前端:前端架构的新趋势
后端
吴尊和7 分钟前
生成长篇小说的朗读语音小说
后端
阿乾之铭7 分钟前
Spring Boot 项目初始化
java·spring boot·后端
顺丰同城前端技术团队1 小时前
用大白话聊Deepseek MoE
前端·人工智能·后端
啊哈灵机一动1 小时前
golang开发的一些注意事项(二·)
后端·面试
chentao1062 小时前
Spring-Boot健康检查的正确打开方式
spring boot
喵手2 小时前
领导让我同事封装一个自定义工具类?结果她说要三小时...
java·后端·java ee
程序小武2 小时前
Python面向对象编程:特殊方法深度实践
后端
OnlyLowG2 小时前
SpringSecurity 灵活管控:特定用户单一设备登录机制
后端
钟琛......2 小时前
Java事务失效(面试题)的常见场景
java·数据库·spring