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");
}
}