# Test
# 简介
使用 Spring Test 和 Spring Boot 特性来测试。将从一个应用程序上下文成功加载的简单测试开始,然后使用 Spring 的 MockMvc继续测试web层。
项目搭建就不再赘述,web项目即可。
<?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 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.2.2.RELEASE</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<groupId>com.example</groupId>
<artifactId>testing-web</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>testing-web</name>
<description>Demo project for Spring Boot</description>
<properties>
<java.version>1.8</java.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
<exclusions>
<exclusion>
<groupId>org.junit.vintage</groupId>
<artifactId>junit-vintage-engine</artifactId>
</exclusion>
</exclusions>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
</project>
# 被测试Controller
@RestController
public class HelloController {
@GetMapping("/hello")
public String hello() {
return "Hello World";
}
}
# 测试用例
@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)
@Slf4j
public class HttpRequestTest {
@LocalServerPort
private int port;
@Autowired
private TestRestTemplate restTemplate;
@Test
public void greetingShouldReturnDefaultMessage() throws Exception {
String s = restTemplate.getForObject("http://localhost:" + port + "/hello", String.class);
assertThat(s).contains("Hello World");
log.info(port+"");
}
}
@SpringBootTest注释告诉Spring Boot查找一个主要的配置类(例如,一个带有@SpringBootApplication的类),然后使用该类来启动Spring应用程序上下文。您可以在IDE或命令行中运行此测试(通过运行./mvnw测试或./gradlew测试)。注意,使用
webEnvironment=RANDOM_PORT启动服务器时使用了一个随机端口(这对于避免测试环境中的冲突非常有用),并使用@LocalServerPort注入了该端口。另外,请注意Spring Boot已经自动为您提供了一个TestRestTemplate。你所要做的就是通过@Autowired注入它。
另一种有用的方法是根本不启动服务器,只启动完整的Spring应用程序上下文,只测试其下的层。示例Spring在这一层处理传入的HTTP请求并将其传递给控制器,这样,几乎使用了整个堆栈,代码调用的方式与处理实际HTTP请求的方式完全相同,但是不需要启动服务器。为此,使用Spring的MockMvc,并通过在测试用例上使用@AutoConfigureMockMvc注释请求将其注入。
@SpringBootTest
@AutoConfigureMockMvc// 注入MockMvc
@Slf4j
public class DemoApplicationTests {
@Autowired
private MockMvc mockMvc;
@Test
public void testHello() throws Exception {
ResultActions resultActions = mockMvc.perform(get("/hello").contentType(MediaType.APPLICATION_JSON))
.andDo(print())
.andExpect(status().isOk())
.andExpect(content().string("Hello World"));
String contentAsString = resultActions.andReturn().getResponse().getContentAsString();
log.info(contentAsString);
}
}
我们还可以使用@WebMvcTest将测试范围缩小到web层
@WebMvcTest
@Slf4j
public class HelloControllerTest {
@Autowired
private MockMvc mockMvc;
@Test
public void testHello() throws Exception {
ResultActions resultActions = mockMvc.perform(get("/hello").contentType(MediaType.APPLICATION_JSON))
.andDo(print())
.andExpect(status().isOk())
.andExpect(content().string("Hello World"));
String contentAsString = resultActions.andReturn().getResponse().getContentAsString();
log.info(contentAsString);
}
}
测试断言与前一种情况相同。但是,在这个测试中,Spring Boot只实例化web层,而不是整个上下文。在具有多个控制器的应用程序中,您甚至可以通过使用来请求仅实例化一个控制器。
@WebMvcTest
@Slf4j
public class HelloControllerTest {
private final HelloService service;
public HelloService(HelloService service) {
this.service = service;
}
@Autowired
private MockMvc mockMvc;
@Test
public void testHello() throws Exception {
ResultActions resultActions = mockMvc.perform(get("/hello").contentType(MediaType.APPLICATION_JSON))
.andDo(print())
.andExpect(status().isOk())
.andExpect(content().string("Hello World"));
String contentAsString = resultActions.andReturn().getResponse().getContentAsString();
log.info(contentAsString);
}
}
Spring自动将服务依赖项注入控制器(构造器自动注入,详细查看Spring章节)
我们可以使用@MockBean为HelloService创建和注入一个mock(如果不这样做,应用程序上下文将无法启动)
@WebMvcTest
@Slf4j
public class HelloControllerTest {
@MockBean
private HelloService service;
@Autowired
private MockMvc mockMvc;
@Test
public void testHello() throws Exception {
ResultActions resultActions = mockMvc.perform(get("/hello").contentType(MediaType.APPLICATION_JSON))
.andDo(print())
.andExpect(status().isOk())
.andExpect(content().string("Hello World"));
String contentAsString = resultActions.andReturn().getResponse().getContentAsString();
log.info(contentAsString);
}
}
# 总结
# @SpringBootTest
注释告诉Spring Boot查找一个主要的配置类(例如,一个带有@SpringBootApplication的类),然后使用该类来启动Spring应用程序上下文。
# @WebMvcTest
仅用于测试控制器层,您需要使用模拟对象提供所需的剩余依赖项。
# @DataJpaTest
for testing the repository layer
# @RestClientTests
for testing REST clients
# @JsonTest
for testing the JSON marshalling and unmarshalling