web-dev-qa-db-fra.com

Spring RestTemplate invoque le service Web avec des erreurs et analyse le code d'état

J'ai conçu un service Web pour effectuer une tâche si les paramètres de la demande sont OK, ou retourner le code d'état HTTP 401 non autorisé si les paramètres de la demande sont incorrects ou vides.

J'utilise RestTemplate pour effectuer un test et je peux vérifier l'état HTTP 200 OK si le service Web répond avec succès. Je ne suis cependant pas en mesure de tester l'erreur HTTP 401 car RestTemplate lui-même lève une exception.

Ma méthode de test est

@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());
}

Le journal des exceptions est

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)

Comment puis-je tester si le service Web répond avec un code d'état HTTP 401?

30
Premier

Vous devez implémenter ResponseErrorHandler afin d'intercepter le code de réponse, le corps et l'en-tête lorsque vous obtenez des codes de réponse non 2xx du service à l'aide du modèle de repos. Copiez toutes les informations dont vous avez besoin, joignez-les à votre exception personnalisée et jetez-les afin de pouvoir les saisir dans votre 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;
    }
}

Maintenant, ce que vous devez faire dans votre test est, définissez ce ResponseErrorHandler dans RestTemplate comme,

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]"));
}
48
nilesh

Comme alternative à la solution présentée par nilesh, vous pouvez également utiliser la classe Spring DefaultResponseErrorHandler. Vous devez également remplacer sa méthode hasError (HttpStatus) afin qu'il ne lève pas d'exception sur les résultats non réussis.

restTemplate.setErrorHandler(new DefaultResponseErrorHandler(){
    protected boolean hasError(HttpStatus statusCode) {
        return false;
    }});
29
Ramps

Dans mon service de repos, j'attrape HttpStatusCodeException au lieu de Exception car HttpStatusCodeException a une méthode pour obtenir le code d'état

catch(HttpStatusCodeException e) {
    log.debug("Status Code", e.getStatusCode());
}
7
ericdemo07

Vous pouvez utiliser Spring-test. C'est beaucoup plus simple:

@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
chaldaean

Depuis Spring 4.3, il existe un RestClientResponseException qui contient les données de réponse HTTP réelles, telles que le code d'état, le corps de la réponse et les en-têtes. Et vous pouvez l'attraper.

RestClientResponseException Java Doc

4
zhouji