SpringBoot 中文手册 --Part IV --41 测试

本文翻译自: https://docs.spring.io/spring-boot/docs/1.5.7.RELEASE/reference/htmlsingle/#boot-features-testing

41 测试

Spring Boot提供一些工具和注解在你测试你的应用时提供帮助。测试支持由两个模块提供;spring-boot-test包含核心项目,而spring-boot-test-autoconfigure支持测试的自动配置。

大多数开发者将只是用spring-boot-starter-test“starter”,它可以导入Spring Boot测试模块以及JUnit,AssertJ,Hamcrest和其他一些有用的库。

41.1 测试范围依赖

如果你使用spring-boot-starter-test“Starter”(在测试范围内),你会发现以下提供的库:

  • JUnit –单元测试Java应用程序的实际标准。
  • Spring Test & Spring Boot Test –SpringBoot应用程序的工具类和集成测试支持。
  • AssertJ –流利的断言库
  • Hamcrest –匹配对象的库(也被称为约束或谓词)。
  • Mockito– Java mocking框架
  • JSONassert–一个JSON断言库
  • JsonPath– 适用于JSON的XPath

| 默认,Spring Boot使用 Mockito 1.x。但是,如果你愿意,也可以使用2.x。

这些是我们通常在编写测试时觉得有用的常用库。如果这些不符合您的需求,您可以自由添加您自己的附加测试依赖项。

41.2 测试Spring应用

依赖注入的一个主要优点是它应该是你的代码更容易进行单元测试。你甚至可以简单的使用new操作符实例化对象,甚至不涉及Spring。您也可以使用mock对象而不是真正的依赖关系。

通常你需要超越“单元测试”,开始“集成测试”(实际上涉及Spring ApplicationContext)。能够在不需要部署应用程序或不需要连接到其他基础架构的情况下执行集成测试就很有用。

Spring框架包含一个专门的测试模块,用于这种集成测试。你可以直接声明一个依赖到org.springframework:spring-test或使用spring-boot-starter-test “Starter”来传递它。

如果你还没有使用过Spring-test模块,那么你应该先阅读Spring框架参考文档的相关部分 。

41.3 测试Spring Boot应用

一个SpringBoot应用程序只是一个Spring ApplicationContext,所以没有什么特别的事情要做以超越你通常使用vanilla spring上下文来做的测试。但要注意的一点是,Spring Boot的外部属性,日志记录和其他功能只有在使用SpringApplication创建时才会默认安装在上下文中。

Spring Boot提供了一个@SpringBootTest注解,当您需要Spring Boot特性时,它可以用作标准Spring-test @ContextConfiguration注解的替代方法。注解的工作原理是通过SpringApplication在测试中创建ApplicationContext.

你可以使用@SpringBootTestwebEnvironment属性来进一步优化测试的运行方式:

  • MOCK –加载一个WebApplicationContext并体用一个模拟Servlet环境。嵌入式Servlet容器在使用此注解时不会启动。如果Servlet API 不在你的类路径上,这个模式将透明地回退到创建一个普通非Web ApplicationContext。可以与@AutoConfigureMockMvc结合使用,用于基于MockMVC的应用程序测试。
  • RANDOM_PORT–加载一个EmbeddedWebApplicationContext并提供一个真正的servlet环境。嵌入式servlet容器启动并在随机端口上监听。
  • DEFINED_PORT–加载一个EmbeddedWebApplicationContext并提供一个真正的servlet环境。嵌入式servlet容器启动并监听定义的端口(即从application.properties或默认端口8080).
  • NONE– 使用SpringApplication加载ApplicationContext,但不提供任何servlet环境(模拟或其他)。

| 如果你的测试是@Transactional,默认情况下它会在每个测试方法结束时回滚事务。但是由于使用RANDOM_PORTDEFINED_PORT这种安排隐式地提供了一个真正的servlet环境,HTTP客户端和服务器将在不同的线程中运行,从而分离事务。在这种情况下,在服务器上启动的任何事务都不会回滚。

| 除了@SpringBootTest之外,还提供了许多其他注解来测试应用程序的更具体的切片,详情参阅下文。

| 不要忘记还要在测试中添加@RunWith(SpringRunner.class),否则注解将被忽略。

41.3.1 检测测试配置

如果您熟悉Spring测试框架,则可以使用@ContextConfiguration(classes = ...)来指定要加载哪个Spring @Configuration。或者,您可能经常在测试中使用嵌套的@Configuration类。

在测试Spring Boot应用程序时,这通常不是必需的。只要您没有明确定义一个配置, Spring Boot的@*Test 注释将自动搜索您的主要配置。

搜索算法从包含测试的包开始工作,直到找到@SpringBootApplication@SpringBootConfiguration注释类。只要你以合理的方式构建你的代码,你的主要配置通常是可以找到的。

如果你想定制主配置,你可以使用一个嵌套的@TestConfiguration类。与嵌套的@Configuration类不同,它将被用来代替应用程序的主要配置,除了应用程序的主要配置之外,还将使用一个嵌套的@TestConfiguration类。

| Spring的测试框架将缓存测试之间的应用程序上下文。因此,只要你的测试共享相同的配置(不管他是如何被发现的),加载上下文的潜在耗时过程将只发生一次。

41.3.2 排除测试配置

如果您的应用程序使用组件扫面,例如,如果使用@SpringBootApplication@ComponentScan,则可能会发现仅为特定测试创建的顶级配置类意外地被拾取。

正如我们上面所看到的,@TestConfiguration可以用在测试的内部类来定制主要配置。当放置在顶级类上时,src/test/java中@TestConfiguration标识的类不应该通过扫描来拾取。您可以在需要的地方明确导入该类:

@RunWith(SpringRunner.class)
@SpringBootTest
@Import(MyTestsConfiguration.class)
public class MyTests {

    @Test
    public void exampleTest() {
        ...
    }

}

| 如果直接使用@ComponentScan(即不通过@SpringBootApplication),则需要使用TypeExcludeFilter注册。有关详情,详参Javadoc。

41.3.3 使用随机端口工作

如果您需要启动完整的运行服务器进行测试,我们建议您使用随机端口。如果您使用@SpringBootTest(webEnvironment=WebEnvironment.RANDOM_PORT),则每次运行测试时都会随机选取一个可用端口。

@SpringBootPort注解可以用来注入用于测试的实际端口。为了方便起见,需要对已启动的服务器进行REST调用的测试还可以@Autowire一个TestRestTemplate,它将解析到正在运行的服务器的相关链接:

import org.junit.Test;
import org.junit.runner.RunWith;

import org.springframework.beans.factory.annotation.Autowired;
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.test.context.junit4.SpringRunner;

import static org.assertj.core.api.Assertions.assertThat;

@RunWith(SpringRunner.class)
@SpringBootTest(webEnvironment = WebEnvironment.RANDOM_PORT)
public class RandomPortExampleTests {

    @Autowired
    private TestRestTemplate restTemplate;

    @Test
    public void exampleTest() {
        String body = this.restTemplate.getForObject("/", String.class);
        assertThat(body).isEqualTo("Hello World");
    }

}

41.3.4 Mocking and spying beans

运行测试时有时需要在应用程序上下文中模拟某些组件。例如,你可能遇到一些开发期间不可用的远程服务器。当你想模拟在真实环境中很难触发的故障时,模拟也是有用的。

Spring Boot包含一个@MockBean注解,可以用来为你的ApplicationContext中的一个bean定义一个Mockito模拟。您可以使用注解来添加新的bean,或者替换一个现有的bean的定义。注解可以直接用于测试类,测试中的字段或@Configuration类和字段。当在字段上使用时,创建的模拟实例也将被注入。Mock beans在没中测试方法后自动重置。

| 只要你的测试使用Spring Boot的测试注解(即@SpringBootTest),该功能就会自动启用。要以不同的安排使用此功能,需要明确添加侦听器:@TestExecutionListeners(MockitoTestExecutionListener.class)

这有一个经典例子是我们使用一个mock实现替换已存在的RemoteServicebean:

import org.junit.*;
import org.junit.runner.*;
import org.springframework.beans.factory.annotation.*;
import org.springframework.boot.test.context.*;
import org.springframework.boot.test.mock.mockito.*;
import org.springframework.test.context.junit4.*;

import static org.assertj.core.api.Assertions.*;
import static org.mockito.BDDMockito.*;

@RunWith(SpringRunner.class)
@SpringBootTest
public class MyTests {

    @MockBean
    private RemoteService remoteService;

    @Autowired
    private Reverser reverser;

    @Test
    public void exampleTest() {
        // RemoteService has been injected into the reverser bean
        given(this.remoteService.someCall()).willReturn("mock");
        String reverse = reverser.reverseSomeCall();
        assertThat(reverse).isEqualTo("kcom");
    }

}

另外,你也可以使用@SpyBean来包装任何现有的bean到Mockito spy

41.3.5 自动配置测试

Spring Boot的自动配置系统使用于应用程序,但有时可能对测试有点太多。只加载测试应用程序的“切片”所需的配置部分通常很有帮助。例如,你想测试Spring MVC 控制器是否正确映射了URL,并且您不希望在这些测试中涉及数据库调用;或者您可能想要测试JPA实体,并且在这些测试运行时对WEB层不感兴趣。

spring-boot-test-autoconfigure模块包含许多注解,可用于自动配置这些“切片”。它们中的每一个都以类似的方式工作,提供了一个@...Test标注,用于加载ApplicationContext和一个或多个@AutoConfigure...注解,可用于定制自动配置设置。

|每个切片加载一组非常有限的自动配置类。如果您需要排除其中一个,大多数@...Test注解提供一个excludeAutoConfiguration属性。或者您可以使用@ImportAutoConfiguration#exclude

| 也可以将@ AutoConfigure ...注释与标准的@SpringBootTest注解一起使用。 如果您对“切片”应用程序不感兴趣,但想要一些自动配置的测试bean,则可以使用此组合。

41.3.6 自动配置JSON测试

要测试对象JSON序列化和反序列化是否按预期工作,可以使用@JsonTest注解。 @JsonTest将自动配置Jackson ObjectMapper,任何@JsonComponent bean和任何Jackson模块。 它也配置Gson,如果你碰巧使用Gson代替而不是Jackson。 如果你需要配置自动配置的元素,你可以使用@AutoConfigureJsonTesters注解。

Spring Boot包含基于AssertJ的帮助程序,它们与JSONassert和JsonPath库一起工作来检查JSON是否如预期的那样。 JacksonTesterGsonTesterBasicJsonTester类可分别用于Jackson,Gson和Strings。 使用@JsonTest时,测试类上的任何助手字段都可以被@Autowired。

import org.junit.*;
import org.junit.runner.*;
import org.springframework.beans.factory.annotation.*;
import org.springframework.boot.test.autoconfigure.json.*;
import org.springframework.boot.test.context.*;
import org.springframework.boot.test.json.*;
import org.springframework.test.context.junit4.*;

import static org.assertj.core.api.Assertions.*;

@RunWith(SpringRunner.class)
@JsonTest
public class MyJsonTests {

    @Autowired
    private JacksonTester json;

    @Test
    public void testSerialize() throws Exception {
        VehicleDetails details = new VehicleDetails("Honda", "Civic");
        // Assert against a `.json` file in the same package as the test
        assertThat(this.json.write(details)).isEqualToJson("expected.json");
        // Or use JSON path based assertions
        assertThat(this.json.write(details)).hasJsonPathStringValue("@.make");
        assertThat(this.json.write(details)).extractingJsonPathStringValue("@.make")
                .isEqualTo("Honda");
    }

    @Test
    public void testDeserialize() throws Exception {
        String content = "{\"make\":\"Ford\",\"model\":\"Focus\"}";
        assertThat(this.json.parse(content))
                .isEqualTo(new VehicleDetails("Ford", "Focus"));
        assertThat(this.json.parseObject(content).getMake()).isEqualTo("Ford");
    }

}
JSON帮助程序类也可以直接在标准的单元测试中使用。 如果不使用@JsonTest,只需在@Before方法中调用helper的initFields方法即可。

41.3.7 自动配置的Spring MVC测试

要测试Spring MVC控制器是否按预期工作,可以使用@WebMvcTest注释。 @WebMvcTest将自动配置Spring MVC基础架构,并将扫描的bean限制为@Controller@ControllerAdvice@JsonComponentFilterWebMvcConfigurerHandlerMethodArgumentResolver。 使用此注解时,不会扫描常规的@Component bean。

通常@WebMvcTest将被限制在单个控制器中,并与@MockBean结合使用,为所需的合作者提供模拟实现。

@WebMvcTest也自动配置MockMvc。 Mock MVC提供了一种快速测试MVC控制器的强大方法,无需启动完整的HTTP服务器。

您还可以通过使用@AutoConfigureMockMvc注释来在非@WebMvcTest(例如SpringBootTest)中自动配置MockMvc。
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"));
    }

}
如果需要配置自动配置的元素(例如,应应用servlet过滤器),则可以使用@AutoConfigureMockMvc注释中的属性。

如果使用HtmlUnit或Selenium,则自动配置还将提供WebClient bean和/或WebDriver bean。 这里是一个使用HtmlUnit的例子:

import com.gargoylesoftware.htmlunit.*;
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.*;

@RunWith(SpringRunner.class)
@WebMvcTest(UserVehicleController.class)
public class MyHtmlUnitTests {

    @Autowired
    private WebClient webClient;

    @MockBean
    private UserVehicleService userVehicleService;

    @Test
    public void testExample() throws Exception {
        given(this.userVehicleService.getVehicleDetails("sboot"))
                .willReturn(new VehicleDetails("Honda", "Civic"));
        HtmlPage page = this.webClient.getPage("/sboot/vehicle.html");
        assertThat(page.getBody().getTextContent()).isEqualTo("Honda Civic");
    }

}
默认情况下,Spring Boot会把WebDriver bean放在一个特殊的“范围”中,以确保在每次测试后驱动程序都退出,并注入新的实例。 如果你不想要这个行为,你可以在你的WebDriver @Bean定义中添加@Scope(“singleton”)

可以在附录中找到由@WebMvcTest启用的自动配置列表。

41.3.8 自动配置的Data JPA 测试

如果你想测试JPA应用程序,可以使用@DataJpaTest。 默认情况下,它将配置内存中的嵌入式数据库,扫描@Entity类并配置Spring Data JPA存储库。 常规的@Component bean将不会被加载到ApplicationContext中。

Data JPA测试是事务性的,默认情况下每次测试结束时回滚,有关更多详细信息,请参阅Spring参考资料中的相关章节。 如果这不是你想要的,你可以按照以下步骤禁用一个测试或整个类的事务管理:

import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.boot.test.autoconfigure.orm.jpa.DataJpaTest;
import org.springframework.test.context.junit4.SpringRunner;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;

@RunWith(SpringRunner.class)
@DataJpaTest
@Transactional(propagation = Propagation.NOT_SUPPORTED)
public class ExampleNonTransactionalTests {

}

Data JPA测试也可能注入一个TestEntityManager bean,它提供了专门为测试而设计的标准JPA EntityManager的替代方案。 如果你想在@DataJpaTests之外使用TestEntityManager,你也可以使用@AutoConfigureTestEntityManager注解。 如果您需要,JdbcTemplate也可用。

import org.junit.*;
import org.junit.runner.*;
import org.springframework.boot.test.autoconfigure.orm.jpa.*;

import static org.assertj.core.api.Assertions.*;

@RunWith(SpringRunner.class)
@DataJpaTest
public class ExampleRepositoryTests {

    @Autowired
    private TestEntityManager entityManager;

    @Autowired
    private UserRepository repository;

    @Test
    public void testExample() throws Exception {
        this.entityManager.persist(new User("sboot", "1234"));
        User user = this.repository.findByUsername("sboot");
        assertThat(user.getUsername()).isEqualTo("sboot");
        assertThat(user.getVin()).isEqualTo("1234");
    }

}

内存中的嵌入式数据库通常可以很好地用于测试,因为它们速度快,不需要任何开发者安装。 但是,如果您希望针对真实数据库运行测试,则可以使用@AutoConfigureTestDatabase注解:

@RunWith(SpringRunner.class)
@DataJpaTest
@AutoConfigureTestDatabase(replace=Replace.NONE)
public class ExampleRepositoryTests {

    // ...

}

可以在附录中找到由@DataJpaTest启用的自动配置列表。

41.3.9 自动配置的JDBC测试

@JdbcTest类似于@DataJpaTest除了对于纯jdbc相关的测试。 默认情况下,它也将配置一个内存嵌入式数据库和一个JdbcTemplate。 常规的@Component bean将不会被加载到ApplicationContext中。

JDBC测试是事务性的,默认在每个测试结束时回滚,请参阅Spring参考资料中的相关章节以获取更多细节。 如果这不是你想要的,你可以按照以下步骤禁用一个测试或整个类的事务管理:

import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.boot.test.autoconfigure.jdbc.JdbcTest;
import org.springframework.test.context.junit4.SpringRunner;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;

@RunWith(SpringRunner.class)
@JdbcTest
@Transactional(propagation = Propagation.NOT_SUPPORTED)
public class ExampleNonTransactionalTests {

}

如果你喜欢你的测试运行在一个真实的数据库上,你可以像DataJpaTest一样使用@AutoConfigureTestDatabase注释。

@JdbcTest启用的自动配置列表可以在附录中找到。

41.3.10 自动配置的数据MongoDB 测试;

如果要测试MongoDB应用程序,可以使用@DataMongoTest。 默认情况下,它将配置内存中嵌入的MongoDB(如果可用),配置MongoTemplate,扫描@Document类并配置Spring Data MongoDB存储库。 常规的@Componentbean将不会被加载到ApplicationContext中:

import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.autoconfigure.data.mongo.DataMongoTest;
import org.springframework.data.mongodb.core.MongoTemplate;
import org.springframework.test.context.junit4.SpringRunner;

@RunWith(SpringRunner.class)
@DataMongoTest
public class ExampleDataMongoTests {

    @Autowired
    private MongoTemplate mongoTemplate;

    //
}

内存中的嵌入式MongoDB通常适用于测试,因为它速度快,不需要任何开发人员的安装。 但是,如果您希望针对真正的MongoDB服务器运行测试,则应该排除嵌入式MongoDB自动配置:

import org.junit.runner.RunWith;
import org.springframework.boot.autoconfigure.mongo.embedded.EmbeddedMongoAutoConfiguration;
import org.springframework.boot.test.autoconfigure.data.mongo.DataMongoTest;
import org.springframework.test.context.junit4.SpringRunner;

@RunWith(SpringRunner.class)
@DataMongoTest(excludeAutoConfiguration = EmbeddedMongoAutoConfiguration.class)
public class ExampleDataMongoNonEmbeddedTests {

}

@DataMongoTest启用的自动配置列表可以在附录中找到。

41.3.11 自动配置的REST 客户端

如果您想测试REST客户端,则可以使用@RestClientTest注解。 默认情况下,它会自动配置Jackson和GSON支持,配置RestTemplateBuilder并添加对MockRestServiceServer的支持。 应该使用@RestClientTestvaluecomponents属性指定要测试的特定bean:

@RunWith(SpringRunner.class)
@RestClientTest(RemoteVehicleDetailsService.class)
public class ExampleRestClientTest {

    @Autowired
    private RemoteVehicleDetailsService service;

    @Autowired
    private MockRestServiceServer server;

    @Test
    public void getVehicleDetailsWhenResultIsSuccessShouldReturnDetails()
            throws Exception {
        this.server.expect(requestTo("/greet/details"))
                .andRespond(withSuccess("hello", MediaType.TEXT_PLAIN));
        String greeting = this.service.callRestService();
        assertThat(greeting).isEqualTo("hello");
    }

}

@RestClientTest启用的自动配置列表可以在附录中找到。

41.3.12 自动配置和的Spring REST Docs测试

如果您想在测试中使用Spring REST Docs,可以使用@AutoConfigureRestDocs注释。 它会自动配置MockMvc来使用Spring REST Docs,并删除对Spring REST Docs的JUnit规则的需求。

import org.junit.Test;
import org.junit.runner.RunWith;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.autoconfigure.web.servlet.WebMvcTest;
import org.springframework.http.MediaType;
import org.springframework.test.context.junit4.SpringRunner;
import org.springframework.test.web.servlet.MockMvc;

import static org.springframework.restdocs.mockmvc.MockMvcRestDocumentation.document;
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.*;

@RunWith(SpringRunner.class)
@WebMvcTest(UserController.class)
@AutoConfigureRestDocs("target/generated-snippets")
public class UserDocumentationTests {

    @Autowired
    private MockMvc mvc;

    @Test
    public void listUsers() throws Exception {
        this.mvc.perform(get("/users").accept(MediaType.TEXT_PLAIN))
                .andExpect(status().isOk())
                .andDo(document("list-users"));
    }

}

除了配置输出目录之外,@AutoConfigureRestDocs还可以配置将显示在任何记录的URI中的主机,方案和端口。 如果您需要更多地控制Spring REST Docs的配置,可以使用RestDocsMockMvcConfigurationCustomizer bean:

@TestConfiguration
static class CustomizationConfiguration
        implements RestDocsMockMvcConfigurationCustomizer {

    @Override
    public void customize(MockMvcRestDocumentationConfigurer configurer) {
        configurer.snippets().withTemplateFormat(TemplateFormats.markdown());
    }

}

如果要使用Spring REST Docs对参数化输出目录的支持,可以创建一个RestDocumentationResultHandler bean。 自动配置将使用此结果处理程序调用alwaysDo,从而导致每个MockMvc调用自动生成默认片段:

@TestConfiguration
static class ResultHandlerConfiguration {

    @Bean
    public RestDocumentationResultHandler restDocumentation() {
        return MockMvcRestDocumentation.document("{method-name}");
    }

}

41.3.13 使用Spock测试Spring Boot应用

如果您希望使用Spock来测试Spring Boot应用程序,则应该在Spock的spock-spring模块中添加对应用程序构建的依赖关系。 Spock-Spring将Spring的测试框架集成到Spock中。 具体如何使用Spock来测试Spring Boot应用程序取决于您正在使用的Spock版本。

Spring Boot为Spock 1.0提供依赖管理。 如果你想使用Spock 1.1,你应该重写build.gradle或者pom.xml文件中的 spock.version 属性。

使用Spock 1.1时,只能使用上述注释,并且可以使用@SpringBootTest注释您的Specification 以适合您的测试需求。

使用Spock 1.0时,@SpringBootTest将不适用于Web项目。 你需要使用@SpringApplicationConfiguration@WebIntegrationTest(randomPort = true)。 无法使用@SpringBootTest意味着您也失去了自动配置的TestRestTemplate bean。 您可以使用以下配置自行创建等价的bean:

@Configuration
static class TestRestTemplateConfiguration {

    @Bean
    public TestRestTemplate testRestTemplate(
            ObjectProvider builderProvider,
            Environment environment) {
        RestTemplateBuilder builder = builderProvider.getIfAvailable();
        TestRestTemplate template = builder == null ? new TestRestTemplate()
                : new TestRestTemplate(builder.build());
        template.setUriTemplateHandler(new LocalHostUriTemplateHandler(environment));
        return template;
    }

}

41.4 测试工具

一些测试实用程序类被封装为spring-boot的一部分,在测试应用程序时通常很有用。

41.4.1 ConfigFileApplicationContextInitializer

ConfigFileApplicationContextInitializer是一个ApplicationContextInitializer,它可以应用到你的测试来加载Spring Boot的application.properties文件。 当你不需要@SpringBootTest提供的完整功能时,可以使用它。

@ContextConfiguration(classes = Config.class,
    initializers = ConfigFileApplicationContextInitializer.class)
单独使用ConfigFileApplicationContextInitializer不会提供对@Value("$ {...}")注入的支持。 唯一的工作是确保application.properties文件被加载到Spring的Environment中。 对于@Value支持,您需要另外配置一个PropertySourcesPlaceholderConfigurer或使用@SpringBootTest,其中一个将自动为您配置。

41.4.2 EnvironmentTestUtils

EnvironmentTestUtils允许您快速将属性添加到ConfigurableEnvironmentConfigurableApplicationContext。 只需使用key = value字符串调用它即可:

EnvironmentTestUtils.addEnvironment(env, "org=Spring", "name=Boot");

41.4.3 OutputCapture

OutputCapture是一个JUnit Rule,可以用来捕获System.outSystem.err输出。 只需将捕获声明为@Rule,然后使用toString()进行断言:

import org.junit.Rule;
import org.junit.Test;
import org.springframework.boot.test.rule.OutputCapture;

import static org.hamcrest.Matchers.*;
import static org.junit.Assert.*;

public class MyTest {

    @Rule
    public OutputCapture capture = new OutputCapture();

    @Test
    public void testName() throws Exception {
        System.out.println("Hello World!");
        assertThat(capture.toString(), containsString("World"));
    }

}

41.4.4 TestRestTemplate

TestRestTemplate是Spring RestTemplate的一个方便选择,在集成测试中很有用。 您可以获得一个vanilla template或一个发送Basic HTTP认证(使用用户名和密码)的模板。 无论哪种情况,模板都将以适合测试的方式运行,不会在服务器端错误上抛出异常。 建议使用Apache HTTP Client(版本4.3.2或更高版本),但不是强制性的,如果你的类路径上有TestRestTemplate,则通过适当地配置客户端来做出响应。 如果您使用Apache的HTTP客户端,则会启用一些额外的测试友好功能:

  • 重定向不会被遵循(所以你可以断言响应位置)
  • Cookie将被忽略(所以模板是无状态的)

TestRestTemplate可以在集成测试中直接实例化:

public class MyTest {

    private TestRestTemplate template = new TestRestTemplate();

    @Test
    public void testRequest() throws Exception {
        HttpHeaders headers = template.getForEntity("http://myhost.com/example", String.class).getHeaders();
        assertThat(headers.getLocation().toString(), containsString("myotherhost"));
    }

}

另外,如果您使用带有WebEnvironment.RANDOM_PORTWebEnvironment.DEFINED_PORT的@SpringBootTest注解,则只需注入完全配置的TestRestTemplate并开始使用它。 如有必要,可以通过RestTemplateBuilder bean应用其他自定义设置。 任何不指定主机和端口的URL都将自动连接到嵌入式服务器:

@RunWith(SpringRunner.class)
@SpringBootTest
public class MyTest {

    @Autowired
    private TestRestTemplate template;

    @Test
    public void testRequest() throws Exception {
        HttpHeaders headers = template.getForEntity("/example", String.class).getHeaders();
        assertThat(headers.getLocation().toString(), containsString("myotherhost"));
    }

    @TestConfiguration
    static class Config {

        @Bean
        public RestTemplateBuilder restTemplateBuilder() {
            return new RestTemplateBuilder()
                .additionalMessageConverters(...)
                .customizers(...);
        }

    }

}

你可能感兴趣的:(SpringBoot,spring,测试,spring-boot)