springboot junit Unit-Testing(via spring-boot-starter-test)

SpringBoot Testing

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 官方文档

springboot junit Unit-Testing(via spring-boot-starter-test)_第1张图片
Maven Dependency

直接添加这个依赖即可。

<dependency>
	<groupId>org.springframework.bootgroupId>
	<artifactId>spring-boot-starter-testartifactId>
	<scope>testscope>
dependency>

SpringBoot Application

没什么特别的,跟往常一样,无需额外配置。

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

TestController

新建一个方法,返回一些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);
    }
}

UnitTest.java

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部分:

  • WebEnvironment.MOCK(默认):加载Web的ApplicationContext并提供模拟Web环境。 使用此批注时,不会启动嵌入式服务器例如Tomcat。 如果类路径上没有Web环境,则此模式将透明地回退到创建常规非Web ApplicationContext。 它可以与@AutoConfigureMockMvc或@AutoConfigureWebTestClient结合使用,以进行基于模拟的Web应用程序测试。
  • WebEnvironment.RANDOM_PORT建议!):加载WebServerApplicationContext 并提供一个真实的Web环境,内嵌的服务器例如Tomcat将会使用随机端口进行监听,可以用 @LocalServerPort 获取当前随机的端口号。
  • WebEnvironment.DEFINED_PORT:加载WebServerApplicationContext 并提供一个真实的Web环境,内嵌的服务器例如Tomcat将会从application.yml等配置文件加载,万一没有则默认8080。
  • WebEnvironment.NONE:通过SpringApplication加载ApplicationContext给你,但不提供任何Web环境以及启用任何服务器。

那么,怎么调用Contoller中方法的URL呢?

  • TestRestTemplate,for WebMVC testing。TestRestTemplate是Spring的RestTemplate的一种便利替代品,可用于单元测试/集成测试。在任何一种情况下,模板都以一种测试友好的方式运行,不会在服务器端错误上抛出异常。建议(默认,但不是强制性的)使用Apache HTTP Client(版本4.3.2或更高版本)。可以直接在集成测试中实例化,忽然cookie(因此模板是无状态的),不遵循重定向(Redirects are not followed,因此您可以断言响应位置)。
  • WebTestClient,for 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"));
	}

}

你可能感兴趣的:(Spring,SpringBoot2启示录,springboot,junit,test,springboot,unit,testing,springboot,单元测试,springboot)