SpringBoot单元测试

本文基于springboot 2.4.5介绍基于spring-boot-starter-test进行单元测试的基本方法。

1. 普通方式测试service层及普通Bean

2. mock方式测试controller层

目录

1. 单元测试范围

2. 搭建测试项目引入maven库

3. 待测Service及Controller代码如下

User.java

UserService.java

UserServiceImpl.java

UserController.java

4. 编写Service测试类

5. 编写Controller测试类


1. 单元测试范围

controller,service,核心Bean(重要算法,重要工具类)

2. 搭建测试项目引入maven库

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

3. 待测Service及Controller代码如下

代码结构如下:

User.java

public class User {
	private int id;
	private String username;
	private String password;
	/*
        constructor
        getter
        setter
        */
}

UserService.java

public interface UserService {
	public User getUser(int id);
	public List<User> getUsersBySubname(String subname);
}

包含两个待测函数,一个是获取单个实体,一个获取实体集合。

UserServiceImpl.java

@Service
public class UserServiceImpl implements UserService {

	@Override
	public User getUser(int id) {
		// 这里模拟一下数据库查询
		User user = new User(1, "user1", "user1");
		return user;
	}

	@Override
	public List<User> getUsersBySubname(String subname) {
		List<User> users = new ArrayList<>();
		users.add(new User(1, "user1", "user1"));
		users.add(new User(2, "user2", "user2"));
		return users;
	}
	
}

UserController.java

@RestController
@RequestMapping("/")
public class UserController {
	
	@Autowired
	private UserService userService;
	
	public UserController(UserService userService) {
		this.userService = userService;
	}
	
	@GetMapping("/user/{id}")
	public User getUser(@PathVariable int id) {
		User user = userService.getUser(1);
		return user;
	}
	
	@GetMapping("/users")
	public List<User> getUsers(@RequestParam String subname) {
		List<User> users = userService.getUsersBySubname(subname);
		return users;
	}

}

同样包含两个待测Controller,一个是传入路径参数,一个传入请求参数。为后面单元测试做不同参数的传入做准备。

运行查看服务是否正常,结果如下:

4. 编写Service测试类

新建Test文件,存放路径如下,命名推荐以待测类名称+Test命名。

单元测试类上注解:@SpringBootTest,表明这是一个SpringBoot的单元测试类。

待测类上注解:@Autowired,因为都还是基于Spring容器管理,所以依然使用自动装配获取待测对象。

单元测试函数上注解:@Test,表明这是个单元测试方法。里面写要测试的逻辑,之后用assertXxxx()来判断输出是否符合预期。

具体代码如下:

 

@SpringBootTest
class UserServieTest {

	@Autowired
	private UserService userService;
	
	@Test
	void getUserTest() {
		User user = userService.getUser(1);
		assertNotNull(user);
	}
	
	@Test
	void getUsersTest() {
		List<User> users = userService.getUsersBySubname("user");
		assertEquals(users.size(), 3);
	}
}

该文件中右键,Run as junit test,即可执行查看结果。

全部通过则显示绿色。

否则显示红色,并标出错误Test

5. 编写Controller测试类

Controller因为主要是处理网络请求的,这里测试需要模拟网络请求作为输入,传统的方式有可以通过RestTemlate进行测试。这里主要介绍MockMvc的方式模拟请求。

Spring测试框架提供MockMvc对象,可以在不需要客户端-服务端请求的情况下进行MVC测试,完全在服务端这边就可以执行Controller的请求,跟启动了测试服务器一样。

测试开始之前需要建立测试环境,setup方法被@Before修饰。通过MockMvcBuilders工具,使用WebApplicationContext对象作为参数,创建一个MockMvc对象。

然后基于mockMvc对象进行请求模拟和结果断言。

具体代码如下:

package com.daicy.test.controller;

import static org.springframework.test.web.servlet.result.MockMvcResultHandlers.print;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.jsonPath;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;

import org.junit.jupiter.api.BeforeEach;
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.test.web.servlet.request.MockMvcRequestBuilders;
import org.springframework.test.web.servlet.setup.MockMvcBuilders;
import org.springframework.web.context.WebApplicationContext;

/**
    * @author daicy
*/

@SpringBootTest
public class UserControllerTest {

    MockMvc mockMvc;

    @Autowired
    WebApplicationContext wc;
    
    @BeforeEach
    public void beforeSetUp() {
        this.mockMvc = MockMvcBuilders.webAppContextSetup(wc).build();
    }
    
    @Test
    void getUserByIdTest() throws Exception {
        this.mockMvc.perform(
                MockMvcRequestBuilders.get("/user/{id}", "1"))
                .andDo(print())
                .andExpect(status().isOk())
                .andExpect(jsonPath("$.id").value("1"))
                .andExpect(jsonPath("$.username").isNotEmpty())
                .andReturn();
    }
    
    @Test
    void getUsersTest() throws Exception {
        this.mockMvc.perform(
                MockMvcRequestBuilders.get("/users")
                .param("subname", "user"))
                .andDo(print())
                .andExpect(status().isOk())
                .andExpect(jsonPath("$").isNotEmpty())
                .andReturn();
    }
}

其中,路径参数直接作为请求函数参数写入,请求参数需要链式一个param(key, value)。

andExpect负责做结果断言,其中Restapi返回的Json信息,用jsonPath可以解析。

断言方式还有很多,可以根据需要自行选取。

最后andReturn()可以返回MvcResult,里面有更详细的请求和响应信息,具体可以看由andDo(print())在控制台打印出的信息:

如果需要更详细的信息判断,可以把MvcResult接回来,然后基于assertXxx继续判断内部详细信息。

至此,简单的Controller和Service单元测试介绍完毕。

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值