使用TestRestTemplate的Spring Boot控制器测试始终会因端点返回404而失败

时间:2020-03-03 14:08:21

标签: spring-boot kotlin spring-boot-test

我正在尝试使用TestRestTemplate创建一个Spring Boot控制器的测试。要求仅将控制器绝对需要的内容包括在测试上下文中,因此,将测试的整个应用程序上下文细化是不可行的。

当前,由于端点返回404,因此测试失败。该端点在生产中正常工作。似乎该控制器未在Web Servlet中注册。

控制器显示如下:

@RestController
class MyController {
    @GetMapping("/endpoint")
    fun endpoint(): ResponseDto {
        return ResponseDto(data = "Some data")
    }
}

data class ResponseDto(val data: String)

测试如下:

@SpringBootTest(
    classes = [MyController::class, ServletWebServerFactoryAutoConfiguration::class],
    webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT
)
internal class MyControllerTestRestTemplateTest(
    @Autowired private val restTemplate: TestRestTemplate
) {
    @Test
    fun `should work`() {
        val result = restTemplate.getForEntity("/endpoint", String::class.java)

        result.body.shouldMatchJson(
            """
                {
                    "data": "Some data"
                }
            """)
    }
}

如何使此测试设置正常工作?

3 个答案:

答案 0 :(得分:0)

要求仅将控制器绝对需要的内容包括在测试上下文中,...

SpringBoot已经为此提供了工具-请参见@WebMvcTest slice documentationthis SO answer

答案 1 :(得分:0)

根据您的要求:

要求仅对 控制器包含在测试环境中,因此将整个 测试的应用程序上下文不是一个选择。

您应该考虑使用@WebMvcTest仅测试Web层。使用当前的@SpringBootTest和随机端口,您将引导整个Spring Context并启动嵌入式Tomcat。使用@WebMvcTest,您可以插入MockMvc实例,并在响应正文/标头/状态上声明内容。

一个Java示例可能看起来像这样

@WebMvcTest(MyController.class)
class MyControllerTests {

    @Autowired
    private MockMvc mvc;

    @Test
    void testExample() throws Exception {
        this.mvc.perform(get("/endpoint")
                .accept(MediaType.APPLICATION_JSON))
                .andExpect(status().isOk())
                .andExpect(content().string("YOUR_STRING_HERE"));
    }
}

一个有效的Kotlin示例如下所示

@WebMvcTest(MyController::class)
internal class MyControllerTests(@Autowired private val mockMvc: MockMvc) {

  @Test
  fun testExample() {
    this.mockMvc.perform(MockMvcRequestBuilders.get("/endpoint")
      .accept(MediaType.APPLICATION_JSON))
      .andExpect(status().isOk)
      .andExpect(content().json("""
        {
         "data": "Some data"
        }
      """.trimIndent()))
  }
}

答案 2 :(得分:0)

rieckpil和Josef的答案都是正确的,我同意使用@WebMvcTest是更好的方法。

如果您坚持继续使用@SpringBootTest和TestRestTemplate:您正在使用webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT。这意味着您的TestRestTemplate不知道要使用哪个端口。您需要在字符串

中包括整个URL,包括应用程序正在运行的端口。

通过添加

@LocalServerPort
int randomServerPort = 0

然后提供完整的网址

val result = restTemplate.getForEntity("http://localhost:${randomServerPort}/endpoint", String::class.java)
相关问题