# 7.9.5. 测试工具

测试应用程序时通常有用的一些测试实用程序类被打包为`spring-boot`.

**7.9.5.1. ConfigDataApplicationContextInitializer**

`ConfigDataApplicationContextInitializer`是一个`ApplicationContextInitializer`你可以应用到你的测试来加载 Spring Boot`application.properties`文件的工具。当您不需要 提供的全套功能时，您可以使用它，`@SpringBootTest`如下例所示：

```java
@ContextConfiguration(classes = Config.class, initializers = ConfigDataApplicationContextInitializer.class)
class MyConfigFileTests {

    // ...

}
```

单独使用`ConfigDataApplicationContextInitializer`不支持`@Value("${…}")`注入。它唯一的工作是确保将`application.properties`文件加载到 Spring 的`Environment`. 为了获得`@Value`支持，您需要另外配置 `PropertySourcesPlaceholderConfigurer`或 `@SpringBootTest`，它会为您自动配置一个。

**7.9.5.2. 测试属性值**

`TestPropertyValues`让您快速将属性添加到 `ConfigurableEnvironment`或`ConfigurableApplicationContext`. 您可以使用`key=value`字符串调用它，如下所示：

```java
class MyEnvironmentTests {

    @Test
    void testPropertySources() {
        MockEnvironment environment = new MockEnvironment();
        TestPropertyValues.of("org=Spring", "name=Boot").applyTo(environment);
        assertThat(environment.getProperty("name")).isEqualTo("Boot");
    }

}
```

**7.9.5.3. 输出捕获**

`OutputCapture`是一个可用于捕获`System.out`和`System.err`输出的 JUnit `Extension`。要使用它，需要添加`@ExtendWith(OutputCaptureExtension.class)`和 injection`CapturedOutput`作为测试类构造函数或测试方法的参数，如下所示：

```java
@ExtendWith(OutputCaptureExtension.class)
class MyOutputCaptureTests {

    @Test
    void testName(CapturedOutput output) {
        System.out.println("Hello World!");
        assertThat(output).contains("World");
    }

}
```

**7.9.5.4. 测试RestTemplate**

`TestRestTemplate`是 Spring 的一种方便替代方案，`RestTemplate`在集成测试中很有用。您可以获得一个普通模板或发送基本 HTTP 身份验证（带有用户名和密码）的模板。在任何一种情况下，模板都是容错的。这意味着它以一种测试友好的方式运行，不会在 4xx 和 5xx 错误上抛出异常。相反，可以通过返回`ResponseEntity`的及其状态码检测此类错误。

Spring Framework 5.0 提供了一个新功能`WebTestClient`，适用于[WebFlux 集成测试](https://docs.spring.io/spring-boot/docs/current/reference/html/features.html#features.testing.spring-boot-applications.spring-webflux-tests)以及[WebFlux 和 MVC 端到端测试](https://docs.spring.io/spring-boot/docs/current/reference/html/features.html#features.testing.spring-boot-applications.with-running-server)。与`TestRestTemplate`不同，它提供了流式的api. 建议使用 Apache HTTP 客户端（版本 4.3.2 或更高版本），但不是强制性的。如果您的类路径中有它，则通过适当地配置客户端来或的`TestRestTemplate`响应。如果您确实使用 Apache 的 HTTP 客户端，则会启用一些额外的测试友好功能：

* 不遵循重定向（因此您可以断言响应位置）。
* Cookie 被忽略（因此模板是无状态的）。

`TestRestTemplate`可以在集成测试中直接实例化，如下例所示：

```java
class MyTests {

    private final TestRestTemplate template = new TestRestTemplate();

    @Test
    void testRequest() {
        ResponseEntity<String> headers = this.template.getForEntity("https://myhost.example.com/example", String.class);
        assertThat(headers.getHeaders().getLocation()).hasHost("other.example.com");
    }

}
```

或者，如果您将`@SpringBootTest`注解与`WebEnvironment.RANDOM_PORT`或`WebEnvironment.DEFINED_PORT`一起使用，您可以注入一个完全配置的`TestRestTemplate`并开始使用它。如有必要，可以通过`RestTemplateBuilder`bean 应用额外的定制。任何未指定主机和端口的 URL 都会自动连接到嵌入式服务器，如下例所示：

```java
@SpringBootTest(webEnvironment = WebEnvironment.RANDOM_PORT)
class MySpringBootTests {

    @Autowired
    private TestRestTemplate template;

    @Test
    void testRequest() {
        HttpHeaders headers = this.template.getForEntity("/example", String.class).getHeaders();
        assertThat(headers.getLocation()).hasHost("other.example.com");
    }

    @TestConfiguration(proxyBeanMethods = false)
    static class RestTemplateBuilderConfiguration {

        @Bean
        RestTemplateBuilder restTemplateBuilder() {
            return new RestTemplateBuilder().setConnectTimeout(Duration.ofSeconds(1))
                    .setReadTimeout(Duration.ofSeconds(1));
        }

    }

}
```
