Skip to content

使用 TestRestTemplate 测试接口

🏷️ Spring Boot Test

TestRestTemplateRestTemplate 的用法类似,其本质上就是封装了 RestTemplate 专供集成测试使用。

只需要在测试类上使用 @SpringBootTest 注解,并且将 webEnvironment 字段指定为 SpringBootTest.WebEnvironment.RANDOM_PORTSpringBootTest.WebEnvironment.DEFINED_PORT ,执行测试方法时就会自动注入 TestRestTemplate 实例。

假设有如下 GET 和 POST 接口:

请求类型URL说明
GET/hello没有参数
GET/hello/{name}从 URL 的 Path 中获取参数
POST/hello从 POST 请求的 Body 中获取参数
POST/hello/from-header从 Header 中获取参数

对应的 HelloController 代码如下:

java
package me.liujiajia.springboot.advanced.rest.template.controller;

import lombok.Data;
import lombok.RequiredArgsConstructor;
import org.springframework.web.bind.annotation.*;

/**
 * @author 佳佳
 */
@RestController
@RequiredArgsConstructor
@RequestMapping("hello")
public class HelloController {

    @GetMapping
    public String sayHello() {
        return "Hello,World!";
    }

    @GetMapping("{name}")
    public String sayHello(@PathVariable String name) {
        return String.format("Hello,%s!", name);
    }

    @PostMapping
    public String sayHello(@RequestBody UserInfo userInfo) {
        return String.format("Hello,%s!", userInfo.getName());
    }

    @PostMapping("from-header")
    public String sayHelloFromHeader(@RequestHeader String name) {
        return String.format("Hello,%s!", name);
    }

    @Data
    public static class UserInfo {
        private String name;
    }
}

对应的测试类 HelloControllerTest 如下:

java
package me.liujiajia.springboot.advanced.rest.template.controller;

import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.Test;
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.http.HttpEntity;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;

@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)
class HelloControllerTest {

    public static final String NAME = "JiaJia";

    /**
     * WebEnvironment.RANDOM_PORT 和 WebEnvironment.DEFINED_PORT 时才会自动注入
     * 详见 TestRestTemplateContextCustomizer.customizeContext() 方法
     */
    @Autowired
    private TestRestTemplate testRestTemplate;

    @Test
    void sayHello() {
        ResponseEntity<String> responseEntity = testRestTemplate.getForEntity("/hello", String.class);

        Assertions.assertEquals(responseEntity.getStatusCode(), HttpStatus.OK);
        Assertions.assertEquals(responseEntity.getBody(), "Hello,World!");
    }

    @Test
    void sayHelloWithName() {
        ResponseEntity<String> responseEntity = testRestTemplate.getForEntity(String.format("/hello/%s", NAME),
                String.class);

        Assertions.assertEquals(responseEntity.getStatusCode(), HttpStatus.OK);
        Assertions.assertEquals(responseEntity.getBody(), String.format("Hello,%s!", NAME));
    }

    @Test
    void sayHelloWithUserInfo() {
        HelloController.UserInfo userInfo = new HelloController.UserInfo();
        userInfo.setName(NAME);

        ResponseEntity<String> responseEntity = testRestTemplate.postForEntity("/hello", userInfo, String.class);

        Assertions.assertEquals(responseEntity.getStatusCode(), HttpStatus.OK);
        Assertions.assertEquals(responseEntity.getBody(), String.format("Hello,%s!", NAME));
    }

    @Test
    void sayHelloWithHeader() {
        HttpHeaders headers = new HttpHeaders();
        headers.add("name", NAME);
        HttpEntity<Object> httpEntity = new HttpEntity<>(headers);

        ResponseEntity<String> responseEntity = testRestTemplate.postForEntity("/hello/from-header",
                httpEntity, String.class);

        Assertions.assertEquals(responseEntity.getStatusCode(), HttpStatus.OK);
        Assertions.assertEquals(responseEntity.getBody(), String.format("Hello,%s!", NAME));
    }

}

上面的示例中分别调用了 TestRestTemplategetForEntity()postForEntity() 方法获取 ResponseEntity ,另外还可通过传递 HttpEntity<> 类型的参数设置请求的 Header

除此之外 TestRestTemplate 还有其他几种类型的 HTTP 请求对应的方法,比较特殊的是 exchange()execute() ,这两个方法支持发送所有类型的请求。

另外,可以在测试目录的 resources 下的 application.yml 文件中指定测试时专用的配置。

比如下面的配置就修改了 org.springframework.web.client 包下的日志级别为 DEBUG 以显示更多的请求信息:

yaml
logging:
  level:
    root: INFO
    org.springframework.web.client: DEBUG

此时运行测试方法会看到类似如下的日志:

java
2022-11-04 16:42:04.181 DEBUG 13356 --- [           main] o.s.web.client.RestTemplate              : HTTP GET http://localhost:63618/hello
2022-11-04 16:42:04.183 DEBUG 13356 --- [           main] o.s.web.client.RestTemplate              : Accept=[text/plain, application/json, application/*+json, */*]
2022-11-04 16:42:04.258  INFO 13356 --- [o-auto-1-exec-1] o.a.c.c.C.[Tomcat].[localhost].[/]       : Initializing Spring DispatcherServlet 'dispatcherServlet'
2022-11-04 16:42:04.258  INFO 13356 --- [o-auto-1-exec-1] o.s.web.servlet.DispatcherServlet        : Initializing Servlet 'dispatcherServlet'
2022-11-04 16:42:04.258  INFO 13356 --- [o-auto-1-exec-1] o.s.web.servlet.DispatcherServlet        : Completed initialization in 0 ms
2022-11-04 16:42:04.310 DEBUG 13356 --- [           main] o.s.web.client.RestTemplate              : Response 200 OK
2022-11-04 16:42:04.311 DEBUG 13356 --- [           main] o.s.web.client.RestTemplate              : Reading to [java.lang.String] as "text/plain;charset=UTF-8"
2022-11-04 16:42:04.334 DEBUG 13356 --- [           main] o.s.web.client.RestTemplate              : HTTP POST http://localhost:63618/hello
2022-11-04 16:42:04.335 DEBUG 13356 --- [           main] o.s.web.client.RestTemplate              : Accept=[text/plain, application/json, application/*+json, */*]
2022-11-04 16:42:04.368 DEBUG 13356 --- [           main] o.s.web.client.RestTemplate              : Writing [HelloController.UserInfo(name=JiaJia)] with org.springframework.http.converter.json.MappingJackson2HttpMessageConverter
2022-11-04 16:42:04.423 DEBUG 13356 --- [           main] o.s.web.client.RestTemplate              : Response 200 OK
2022-11-04 16:42:04.424 DEBUG 13356 --- [           main] o.s.web.client.RestTemplate              : Reading to [java.lang.String] as "text/plain;charset=UTF-8"
2022-11-04 16:42:04.429 DEBUG 13356 --- [           main] o.s.web.client.RestTemplate              : HTTP POST http://localhost:63618/hello/from-header
2022-11-04 16:42:04.429 DEBUG 13356 --- [           main] o.s.web.client.RestTemplate              : Accept=[text/plain, application/json, application/*+json, */*]
2022-11-04 16:42:04.437 DEBUG 13356 --- [           main] o.s.web.client.RestTemplate              : Response 200 OK
2022-11-04 16:42:04.438 DEBUG 13356 --- [           main] o.s.web.client.RestTemplate              : Reading to [java.lang.String] as "text/plain;charset=UTF-8"
2022-11-04 16:42:04.444 DEBUG 13356 --- [           main] o.s.web.client.RestTemplate              : HTTP GET http://localhost:63618/hello/JiaJia
2022-11-04 16:42:04.445 DEBUG 13356 --- [           main] o.s.web.client.RestTemplate              : Accept=[text/plain, application/json, application/*+json, */*]
2022-11-04 16:42:04.451 DEBUG 13356 --- [           main] o.s.web.client.RestTemplate              : Response 200 OK
2022-11-04 16:42:04.451 DEBUG 13356 --- [           main] o.s.web.client.RestTemplate              : Reading to [java.lang.String] as "text/plain;charset=UTF-8"