如何在SpringBoot应用程序的测试目录中创建RestController

时间:2019-02-19 12:51:54

标签: spring-boot spring-mvc spring-test spring-restcontroller spring-boot-test

我目前正在为SpringBoot应用程序编写 集成测试 。 它的功能是从外部接收/发送请求,并将其转发/接收到另一个应用程序(APP_2)。因此,有两个系统需要在System和APP_2之外进行模拟。

ProjectStructure

HomeController

@Controller
public class HomeController {
    @Autowired
    ForwardController forwardController;

    @RequestMapping("/")
    public @ResponseBody
    String greeting() {
    return forwardController.processGET().toString();
    }
}

ForwardController

@Service
public class ForwardController {
    @Autowired
    private RestTemplate restTemplate;

    @Autowired
    private Environment environment;

    private ResponseEntity sendRequest(String url, HttpMethod method, HttpEntity requestEntity, Class responseType, Object... uriVariables) {
    return restTemplate.exchange( url,  method, requestEntity,  responseType,uriVariables);
    }

    public ResponseEntity processGET()
    {
        HttpHeaders headers = new HttpHeaders();
        headers.set("Accept", MediaType.APPLICATION_JSON_VALUE);

        HttpEntity<?> entity = new HttpEntity<>(headers);
        String app_2_url = environment.getProperty(Constants.APP_2_URL);
        ResponseEntity<String> response = sendRequest(app_2_url,HttpMethod.GET,entity,String.class);
        return response;
    }
}

APP_2_CONTROLLER

@Controller
public class App_2_Controller {

    @RequestMapping("/app2Stub")
    public @ResponseBody
    String greeting() {
        return "Hello End of world";
    }
}

测试类,用于模拟系统的外部请求行为:

HTTP_request_Test

@RunWith(SpringRunner.class)
@ActiveProfiles("test")
@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT,classes = Application.class)
public class HttpRequestTest {

    @LocalServerPort
    private int port;

    @Autowired
    private TestRestTemplate restTemplate;

    @Autowired
    private Environment environment;

    @Test
    public void greetingShouldReturnDefaultMessage() throws Exception {
      assertThat(this.restTemplate.getForObject("http://localhost:" + port + "/",
            String.class)).contains("Hello End of world");
    }
}

在此测试类中,我通过具有两个属性文件来覆盖属性。因此,当我们运行测试时,请求将发送到 App_2_Controller (在我的项目中为模拟文件),而不是真实的App。

问题

  1. 是否可以将APP_2_CONTROLLER放入测试文件夹中?这是因为我不想在我的实际应用程序中公开不需要的测试端点。
  2. 在上述项目中,我使用属性更改了URL。是否有更好的方式为相同的URL放置控制器。为了简单起见,假设app_2的网址为 app.com:9000/serve

1 个答案:

答案 0 :(得分:1)

Spring已经附带了MockRestServiceServer,这使它变得容易得多,因此您不必创建自己的虚拟控制器(App_2_Controller)。因此,根据您的情况,您可以删除该控制器,并为ForwardController编写这样的测试:

@RunWith(SpringRunner.class)
@SpringBootTest
@ActiveProfiles("test")
public class ForwardControllerTest {
    @Autowired
    private RestTemplate restTemplate;
    @Autowired
    private ForwardController forwardController; // Your service

    private MockRestServiceServer server;

    @Before
    public void setUp() {
        server = MockRestServiceServer.bindTo(restTemplate).build();
    }

    @Test
    public void processGet_returnsResponseFromAPI() {
        server.expect(once(), requestTo("http://app.com:9000/serve"))
            .andExpect(method(HttpMethod.GET))
            .andRespond(withSuccess("Hello End of world", MediaType.TEXT_PLAIN));
        assertThat(forwardController.processGET().getBody()).isEqualTo("Hello End of world"));
    }
}

此外,您可以为实际的控制器创建单独的测试(ForwardController只是一项服务),模拟ForwardController并使用MockMvc

@RunWith(SpringRunner.class)
@WebMvcTest
public class HomeControllerTest {
    @Autowired
    private HomeController homeController;
    @Autowired
    private MockMvc mockMvc;
    @MockBean
    private ForwardController forwardController;

    @Test
    public void greeting_usesForwardController() {
        when(forwardController.expectGET()).thenReturn("Hello End of world");
        mockMvc.perform(get("/"))
            .andExpect(status().isOk())
            .andExpect(content().string(containsString("Hello End of world")));
    }
}

在这种情况下,您将进行两个测试:

  1. 通过一项测试来验证是否使用RestTemplate来捕获来自外部REST API的正确响应。
  2. 另一项验证HomeController是否转发ForwardController响应的测试。