SpringBoot从入门到精通教程(一)- 如何进行单元测试编写和场景案例分析

需求背景

1. 可以进行自动化测试,配合CI,在项目发布前可以验证功能
2. 尽可能早发现问题,及时修复解决

技术点

主要使用了两个注解

1. @RunWith

2. @SpringBootTest

案例说明

场景案例分析:

1. 普通Java测试,比如配置参数加载,静态方法返回值等

2. 普通Web接口测试

3. 业务服务层代码测试

4. 使用MockMvc测试接口

代码演示

举两个例子

1. 普通Web接口测试

package com.md.demo;

import java.net.URL;

import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.boot.test.web.client.TestRestTemplate;
import org.springframework.boot.web.server.LocalServerPort;
import org.springframework.http.ResponseEntity;
import org.springframework.test.context.junit4.SpringRunner;

import junit.framework.TestCase;

/**
 * 普通Web接口测试
 * 
 * @author Minbo
 *
 */
@RunWith(SpringRunner.class)
@SpringBootTest(classes = Application.class, webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT) // 指定启动类和随机端口
public class ApplicationWebApiTest {

	protected static Logger logger = LoggerFactory.getLogger(ApplicationWebApiTest.class);

	/**
	 * @LocalServerPort 提供了 @Value("${local.server.port}") 的代替
	 */
	@LocalServerPort
	private int port;

	private URL base;

	@Autowired
	private TestRestTemplate restTemplate;

	@Before
	public void setUp() throws Exception {
		String url = String.format("http://localhost:%d/", port);
		logger.info("随机自动分配端口后的整体请求头--->>> " + url);
		this.base = new URL(url);
	}

	/**
	 * 向"/hello"地址发送请求,并打印返回结果
	 * 
	 * @throws Exception
	 */
	@Test
	public void testUrlApi() throws Exception {
		String url = this.base.toString() + "/hello";
		logger.info("待测试接口地址:url=" + url);
		ResponseEntity response = this.restTemplate.getForEntity(url, String.class, "");
		String result = response.getBody();
		logger.info("返回结果:result=" + result);
		boolean expected = false;
		if (result != null && result.contains("sprint-boot2-autotest")) {
			expected = true;
		}
		TestCase.assertEquals(true, expected);
	}
}

2. 使用MockMvc测试接口

package com.md.demo;

import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
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.test.context.junit4.SpringRunner;
import org.springframework.test.context.web.WebAppConfiguration;
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.MockMvcResultMatchers;
import org.springframework.test.web.servlet.setup.MockMvcBuilders;
import org.springframework.web.context.WebApplicationContext;

/**
 * 使用MockMvc测试接口
 * 
 * @author Minbo
 *
 */
@RunWith(SpringRunner.class)
@SpringBootTest(classes = Application.class) // 指定启动类
@AutoConfigureMockMvc // 测试接口用
@WebAppConfiguration
public class ApplicationMockTest {

	protected static Logger logger = LoggerFactory.getLogger(ApplicationMockTest.class);

	@Autowired
	private MockMvc mockMvc;
	@Autowired
	private WebApplicationContext context;

	@Before
	public void setupMockMvc() throws Exception {
		mockMvc = MockMvcBuilders.webAppContextSetup(context).build();
	}

	@Before
	public void testBefore() {
		logger.info("测试前,打印...");
	}

	@After
	public void testAfter() {
		logger.info("测试后,打印...");
	}

	@Test
	public void apiTest() throws Exception {
		String url = "/hello";
		String expectResult = "Hello,greetings from sprint-boot2-autotest";

		MvcResult mvcResult = mockMvc.perform(MockMvcRequestBuilders.get(url))
				// 期望:200成功状态码
				.andExpect(MockMvcResultMatchers.status().isOk())
				// 期望:返回结果数据
				.andExpect(MockMvcResultMatchers.content().string(expectResult)).andReturn();

		int status = mvcResult.getResponse().getStatus();
		logger.info("返回状态码status=" + status);

		String content = mvcResult.getResponse().getContentAsString();
		logger.info("返回结果数据content=" + content);
	}
}

注解说明

@SpringBootTest注解底层实际上还是使用了Junit框架

Junit基本注解介绍
@BeforeClass 在所有测试方法前执行一次,一般在其中写上整体初始化的代码
@AfterClass 在所有测试方法后执行一次,一般在其中写上销毁和释放资源的代码
@Before 在每个测试方法前执行,一般用来初始化方法
@After 在每个测试方法后执行,在方法执行完成后要做的事情
@Test(timeout = 1000) 测试方法执行超过1000毫秒后算超时,测试将失败
@Test(expected = Exception.class) 测试方法期望得到的异常类,如果方法执行没有抛出指定的异常,则测试失败
@Test 编写一般测试用例

完整源码下载

我的Github源码地址:

https://github.com/hemin1003/spring-boot-study/tree/master/spring-boot2-study/spring-boot2-parent

SpringBoot从入门到精通教程(一)- 如何进行单元测试编写和场景案例分析_第1张图片

参考资料

1. https://blog.csdn.net/qq_39508544/article/details/78461020

2. https://blog.csdn.net/fxbin123/article/details/80617754

3. https://www.cnblogs.com/Mblood/p/9699341.html

下一章教程

SpringBoot从入门到精通教程(二)- 拦截器用法和场景案例分析

该系列教程

SpringBoot从入门到精通教程

 

------------------------------------------------------

------------------------------------------------------

 

关于我(个人域名)

我的开源项目集Github

 

期望和大家一起学习,共同进步,共勉,O(∩_∩)O谢谢

欢迎交流问题,可加个人QQ 469580884,

或者,加我的群号 751925591,一起探讨交流问题

不讲虚的,只做实干家

Talk is cheap,show me the code

如果觉得内容赞,您可以请我喝杯咖啡:

        

你可能感兴趣的:(SpringBoot1教程,SpringBoot系列,DevOps实战)