Тест контроллера Spring Boot с TestRestTemplate всегда завершается неудачно, конечные точки возвращают 404 - PullRequest
0 голосов
/ 03 марта 2020

Я пытаюсь создать тест контроллера Spring Boot, используя TestRestTemplate. Требуется, чтобы в контекст теста включалось только то, что абсолютно необходимо для контроллера, поэтому ускорение всего контекста приложения для теста не вариант.

В настоящее время тест завершается неудачно из-за возврата конечной точки 404. Конечная точка работает правильно в производстве. Похоже, что контроллер не регистрируется в веб-сервлете.

Контроллер выглядит следующим образом:

@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 голосов
/ 03 марта 2020

Как указано в вашем требовании:

Требуется, чтобы в контекст теста включалось только то, что абсолютно необходимо для контроллера, поэтому раскрутка всего контекста приложения для теста не является option.

Вы должны рассмотреть возможность тестирования только веб-слоя с использованием @WebMvcTest. Имея текущий @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()))
  }
}
0 голосов
/ 03 марта 2020

Ответы rieckpil и Josef верны, и я согласен, что использование @WebMvcTest - лучший подход.

Если вы продолжаете использовать @SpringBootTest и TestRestTemplate: вы используете webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT. Это означает, что ваш TestRestTemplate не знает, какой порт использовать. Вы должны включить в строку url

весь URL-адрес, включая порт, на котором работает приложение, добавив

@LocalServerPort
int randomServerPort = 0

, а затем указав полный URL-адрес

val result = restTemplate.getForEntity("http://localhost:${randomServerPort}/endpoint", String::class.java)
0 голосов
/ 03 марта 2020

Требуется, чтобы в контекст теста было включено только то, что абсолютно необходимо для контроллера, ...

SpringBoot уже имеет инструменты для этого - см. @WebMvcTest документация среза или этого SO ответа .

...