Spring Boot默认提供了一系列实用工具
和Annotation注释
来帮助您测试应用,可以用来做单元测试Unit Testing
。
测试支持由两个模块提供:spring-boot-test包含核心项,spring-boot-test-autoconfigure支持测试的自动配置。
大多数开发人员使用spring-boot-starter-test
的 Starter 模块,它导入Spring Boot测试模块以及JUnit,AssertJ,Hamcrest和许多其他有用的库。
Spring Boot Testing 官方文档
直接添加这个依赖即可。
<dependency>
<groupId>org.springframework.bootgroupId>
<artifactId>spring-boot-starter-testartifactId>
<scope>testscope>
dependency>
没什么特别的,跟往常一样,无需额外配置。
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
@SpringBootApplication
public class JunitApplication {
public static void main(String[] args) {
SpringApplication.run(JunitApplication.class,args);
}
}
新建一个方法,返回一些JSON数据用于测试即可。
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
import java.util.HashMap;
import java.util.Map;
@RestController
public class TestController {
@GetMapping("/user")
public ResponseEntity user(){
Map<String,Object> user=new HashMap<>(2);
user.put("id","6666");
user.put("createtime",System.currentTimeMillis());
user.put("name","MOSHOW.K.ZHENG");
return ResponseEntity.ok(user);
}
}
Spring Boot应用程序是一个Spring ApplicationContext,因此除了通常使用的Spring上下文之外,还没有什么特别的东西可以用来测试它。
Spring Boot 提供了强大的@SpringBootTest注解,可以直接通过你的SpingApplication注入ApplicationContext,并提供很多可选参数,请看下面的参数解析。
@RunWith(SpringRunner.class) 部分:
JUnit 4
,请不要忘记将@RunWith(SpringRunner.class)
添加到测试中,否则将忽略注释。JUnit 5
,则无需将等效的@ExtendWith(SpringExtension.class)
添加到@SpringBootTest旁边。@SpringBootTest - WebEnvironment部分:
模拟Web
环境。 使用此批注时,不会启动嵌入式服务器例如Tomcat。 如果类路径上没有Web环境,则此模式将透明地回退到创建常规非Web ApplicationContext。 它可以与@AutoConfigureMockMvc或@AutoConfigureWebTestClient结合使用,以进行基于模拟的Web应用程序测试。建议!
):加载WebServerApplicationContext 并提供一个真实
的Web环境,内嵌的服务器例如Tomcat将会使用随机端口进行监听,可以用 @LocalServerPort 获取当前随机的端口号。真实
的Web环境,内嵌的服务器例如Tomcat将会从application.yml等配置文件加载,万一没有则默认8080。那么,怎么调用Contoller中方法的URL呢?
WebMVC
testing。TestRestTemplate
是Spring的RestTemplate
的一种便利替代品,可用于单元测试/集成测试。在任何一种情况下,模板都以一种测试友好的方式运行,不会在服务器端错误上抛出异常。建议(默认,但不是强制性的)使用Apache HTTP Client(版本4.3.2或更高版本)。可以直接在集成测试中实例化,忽然cookie
(因此模板是无状态的),不遵循重定向
(Redirects are not followed,因此您可以断言响应位置)。WebFlux
testing。Spring Framework 5.0提供了一个新的WebTestClient,适用于WebFlux集成测试以及WebFlux和MVC端到端测试。与TestRestTemplate不同,它为断言提供了流畅的API。import com.alibaba.fastjson.JSON;
import com.softdev.system.demo.JunitApplication;
import lombok.extern.slf4j.Slf4j;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.boot.test.context.SpringBootTest.WebEnvironment;
import org.springframework.boot.test.web.client.TestRestTemplate;
import org.springframework.boot.web.server.LocalServerPort;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.test.context.junit4.SpringRunner;
import java.net.URL;
import static org.assertj.core.api.Assertions.assertThat;
@RunWith(SpringRunner.class)
@SpringBootTest(classes={JunitApplication.class},webEnvironment = WebEnvironment.RANDOM_PORT)
@Slf4j
public class UnitTest {
@LocalServerPort
private int port;
private URL base;
private TestRestTemplate template = new TestRestTemplate();
@Before
public void setUp() throws Exception {
String url = String.format("http://127.0.0.1:%d/", port);
System.out.println(String.format("port is : [%d]", port));
this.base = new URL(url);
}
@Test
public void userTest() {
ResponseEntity<String> response = template.getForEntity(this.base.toString() + "/junit/user",String.class,"");
log.info("ResponseEntity:"+ JSON.toJSONString(response));
assertThat(response.getStatusCode()).isEqualTo(HttpStatus.OK);
assertThat(response.getBody()).contains("namex");
log.info("pass unit-testing");
}
@Test
public void userErrorTest() {
ResponseEntity<String> response = template.getForEntity(this.base.toString() + "/junit/user",String.class,"");
log.info("ResponseEntity:"+ JSON.toJSONString(response));
assertThat(response.getStatusCode()).isEqualTo(HttpStatus.OK);
assertThat(response.getBody()).contains("namexxx");
log.info("pass unit-testing");
}
}
官方还提供一种MockMvc的模拟方式,可以让Controller从模拟的Service中获取数据(也可以模拟其他层,例如Repository)
import org.junit.*;
import org.junit.runner.*;
import org.springframework.beans.factory.annotation.*;
import org.springframework.boot.test.autoconfigure.web.servlet.*;
import org.springframework.boot.test.mock.mockito.*;
import static org.assertj.core.api.Assertions.*;
import static org.mockito.BDDMockito.*;
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.*;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.*;
@RunWith(SpringRunner.class)
@WebMvcTest(UserVehicleController.class)
public class MyControllerTests {
@Autowired
private MockMvc mvc;
@MockBean
private UserVehicleService userVehicleService;
@Test
public void testExample() throws Exception {
given(this.userVehicleService.getVehicleDetails("sboot"))
.willReturn(new VehicleDetails("Honda", "Civic"));
this.mvc.perform(get("/sboot/vehicle").accept(MediaType.TEXT_PLAIN))
.andExpect(status().isOk()).andExpect(content().string("Honda Civic"));
}
}