可以将文章内容翻译成中文,广告屏蔽插件可能会导致该功能失效(如失效,请关闭广告屏蔽插件后再试):
问题:
I designed a webservice to perform a task if request parameters are OK, or return 401 Unauthorized HTTP status code if request parameters are wrong or empty.
I'm using RestTemplate
to perform a test and I'm able to verify the HTTP 200 OK status if the webservice replies with success. I am however unable to test for HTTP 401 error because RestTemplate
itself throws an exception.
My test method is
@Test public void testUnauthorized() { Map<String, Object> params = new HashMap<String, Object>(); ResponseEntity response = restTemplate.postForEntity(url, params, Map.class); Assert.assertEquals(HttpStatus.UNAUTHORIZED, response.getStatusCode()); Assert.assertNotNull(response.getBody()); }
Exception log is
org.springframework.web.client.HttpClientErrorException: 401 Unauthorized at org.springframework.web.client.DefaultResponseErrorHandler.handleError(DefaultResponseErrorHandler.java:88) at org.springframework.web.client.RestTemplate.handleResponseError(RestTemplate.java:533) at org.springframework.web.client.RestTemplate.doExecute(RestTemplate.java:489) at org.springframework.web.client.RestTemplate.execute(RestTemplate.java:447) at org.springframework.web.client.RestTemplate.postForEntity(RestTemplate.java:318)
How I can test if webservice replies with a HTTP status code 401?
回答1:
You need to implement ResponseErrorHandler
in order to intercept response code, body, and header when you get non-2xx response codes from the service using rest template. Copy all the information you need, attach it to your custom exception and throw it so that you can catch it in your test.
public class CustomResponseErrorHandler implements ResponseErrorHandler { private ResponseErrorHandler errorHandler = new DefaultResponseErrorHandler(); public boolean hasError(ClientHttpResponse response) throws IOException { return errorHandler.hasError(response); } public void handleError(ClientHttpResponse response) throws IOException { String theString = IOUtils.toString(response.getBody()); CustomException exception = new CustomException(); Map<String, Object> properties = new HashMap<String, Object>(); properties.put("code", response.getStatusCode().toString()); properties.put("body", theString); properties.put("header", response.getHeaders()); exception.setProperties(properties); throw exception; } }
Now what you need to do in your test is, set this ResponseErrorHandler in RestTemplate like,
RestTemplate restclient = new RestTemplate(); restclient.setErrorHandler(new CustomResponseErrorHandler()); try { POJO pojo = restclient.getForObject(url, POJO.class); } catch (CustomException e) { Assert.isTrue(e.getProperties().get("body") .equals("bad response")); Assert.isTrue(e.getProperties().get("code").equals("400")); Assert.isTrue(((HttpHeaders) e.getProperties().get("header")) .get("fancyheader").toString().equals("[nilesh]")); }
回答2:
As an alternative to the solution presented by nilesh, you could also use spring class DefaultResponseErrorHandler. You also need to ovveride its hasError(HttpStatus) method so it does not throw exception on non-successful result.
restTemplate.setErrorHandler(new DefaultResponseErrorHandler(){ protected boolean hasError(HttpStatus statusCode) { return false; }});
回答3:
In my rest service I catch HttpStatusCodeException
instead of Exception
since HttpStatusCodeException
has a method for getting the status code
catch(HttpStatusCodeException e) { log.debug("Status Code", e.getStatusCode()); }
回答4:
You can use spring-test. It's much easier:
@WebAppConfiguration @RunWith(SpringJUnit4ClassRunner.class) @ContextConfiguration("classpath:your-context.xml") public class BasicControllerTest { @Autowired protected WebApplicationContext wac; protected MockMvc mockMvc; @Before public void setUp() throws Exception { mockMvc = MockMvcBuilders.webAppContextSetup(this.wac).build(); } @Test public void testUnauthorized(){ mockMvc.perform(MockMvcRequestBuilders .post("your_url") .param("name", "values") .andDo(MockMvcResultHandlers.print()) .andExpect(MockMvcResultMatchers.status().isUnauthorized() .andExpect(MockMvcResultMatchers.content().string(Matchers.notNullValue())); } }
回答5:
Since Spring 4.3, There is a RestClientResponseException
which contain actual HTTP response data, such as status code, response body and headers. And you can catch it.
RestClientResponseException Java Doc