From be807bab12a6b20033bd5494d63899399a3fdc13 Mon Sep 17 00:00:00 2001 From: Andy Wilkinson Date: Mon, 17 May 2021 11:07:23 +0100 Subject: [PATCH] Polish "Improve documentation of TestRestTemplate's fault tolerance" See gh-26227 --- .../docs/asciidoc/spring-boot-features.adoc | 4 +- .../test/web/client/TestRestTemplate.java | 105 ++++++++---------- 2 files changed, 52 insertions(+), 57 deletions(-) diff --git a/spring-boot-project/spring-boot-docs/src/docs/asciidoc/spring-boot-features.adoc b/spring-boot-project/spring-boot-docs/src/docs/asciidoc/spring-boot-features.adoc index 6277ce8d65..642773ffaa 100644 --- a/spring-boot-project/spring-boot-docs/src/docs/asciidoc/spring-boot-features.adoc +++ b/spring-boot-project/spring-boot-docs/src/docs/asciidoc/spring-boot-features.adoc @@ -7606,7 +7606,9 @@ include::{test-examples}/test/system/OutputCaptureTests.java[tag=test] ==== TestRestTemplate `TestRestTemplate` is a convenience alternative to Spring's `RestTemplate` that is useful in integration tests. You can get a vanilla template or one that sends Basic HTTP authentication (with a username and password). -In either case, the template behaves in a test-friendly way by not throwing exceptions on server-side errors. +In either case, the template is fault tolerant. +This means that it behaves in a test-friendly way by not throwing exceptions on 4xx and 5xx errors. +Instead, such errors can be detected via the returned `ResponseEntity` and its status code. TIP: Spring Framework 5.0 provides a new `WebTestClient` that works for <> and both <>. It provides a fluent API for assertions, unlike `TestRestTemplate`. diff --git a/spring-boot-project/spring-boot-test/src/main/java/org/springframework/boot/test/web/client/TestRestTemplate.java b/spring-boot-project/spring-boot-test/src/main/java/org/springframework/boot/test/web/client/TestRestTemplate.java index 4f4380d097..56dcf3a96f 100644 --- a/spring-boot-project/spring-boot-test/src/main/java/org/springframework/boot/test/web/client/TestRestTemplate.java +++ b/spring-boot-project/spring-boot-test/src/main/java/org/springframework/boot/test/web/client/TestRestTemplate.java @@ -1,5 +1,5 @@ /* - * Copyright 2012-2020 the original author or authors. + * Copyright 2012-2021 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -49,16 +49,19 @@ import org.springframework.util.Assert; import org.springframework.web.client.DefaultResponseErrorHandler; import org.springframework.web.client.RequestCallback; import org.springframework.web.client.ResponseExtractor; -import org.springframework.web.client.RestClientException; import org.springframework.web.client.RestTemplate; import org.springframework.web.util.DefaultUriBuilderFactory; import org.springframework.web.util.UriTemplateHandler; /** * Convenient alternative of {@link RestTemplate} that is suitable for integration tests. - * They are fault tolerant, and optionally can carry Basic authentication headers. If - * Apache Http Client 4.3.2 or better is available (recommended) it will be used as the - * client, and by default configured to ignore cookies and redirects. + * {@code TestRestTemplate} is fault tolerant. This means that 4xx and 5xx do not result + * in an exception being thrown and can instead be detected via the {@link ResponseEntity + * response entity} and its {@link ResponseEntity#getStatusCode() status code}. + *

+ * A {@code TestRestTemplate} can optionally carry Basic authentication headers. If Apache + * Http Client 4.3.2 or better is available (recommended) it will be used as the client, + * and by default configured to ignore cookies and redirects. *

* Note: To prevent injection problems this class intentionally does not extend * {@link RestTemplate}. If you need access to the underlying {@link RestTemplate} use @@ -177,7 +180,7 @@ public class TestRestTemplate { * @return the converted object * @see RestTemplate#getForObject(String, Class, Object...) */ - public T getForObject(String url, Class responseType, Object... urlVariables) throws RestClientException { + public T getForObject(String url, Class responseType, Object... urlVariables) { return this.restTemplate.getForObject(url, responseType, urlVariables); } @@ -193,8 +196,7 @@ public class TestRestTemplate { * @return the converted object * @see RestTemplate#getForObject(String, Class, Object...) */ - public T getForObject(String url, Class responseType, Map urlVariables) - throws RestClientException { + public T getForObject(String url, Class responseType, Map urlVariables) { return this.restTemplate.getForObject(url, responseType, urlVariables); } @@ -207,7 +209,7 @@ public class TestRestTemplate { * @return the converted object * @see RestTemplate#getForObject(java.net.URI, java.lang.Class) */ - public T getForObject(URI url, Class responseType) throws RestClientException { + public T getForObject(URI url, Class responseType) { return this.restTemplate.getForObject(applyRootUriIfNecessary(url), responseType); } @@ -224,8 +226,7 @@ public class TestRestTemplate { * @see RestTemplate#getForEntity(java.lang.String, java.lang.Class, * java.lang.Object[]) */ - public ResponseEntity getForEntity(String url, Class responseType, Object... urlVariables) - throws RestClientException { + public ResponseEntity getForEntity(String url, Class responseType, Object... urlVariables) { return this.restTemplate.getForEntity(url, responseType, urlVariables); } @@ -241,8 +242,7 @@ public class TestRestTemplate { * @return the converted object * @see RestTemplate#getForEntity(java.lang.String, java.lang.Class, java.util.Map) */ - public ResponseEntity getForEntity(String url, Class responseType, Map urlVariables) - throws RestClientException { + public ResponseEntity getForEntity(String url, Class responseType, Map urlVariables) { return this.restTemplate.getForEntity(url, responseType, urlVariables); } @@ -255,7 +255,7 @@ public class TestRestTemplate { * @return the converted object * @see RestTemplate#getForEntity(java.net.URI, java.lang.Class) */ - public ResponseEntity getForEntity(URI url, Class responseType) throws RestClientException { + public ResponseEntity getForEntity(URI url, Class responseType) { return this.restTemplate.getForEntity(applyRootUriIfNecessary(url), responseType); } @@ -268,7 +268,7 @@ public class TestRestTemplate { * @return all HTTP headers of that resource * @see RestTemplate#headForHeaders(java.lang.String, java.lang.Object[]) */ - public HttpHeaders headForHeaders(String url, Object... urlVariables) throws RestClientException { + public HttpHeaders headForHeaders(String url, Object... urlVariables) { return this.restTemplate.headForHeaders(url, urlVariables); } @@ -281,7 +281,7 @@ public class TestRestTemplate { * @return all HTTP headers of that resource * @see RestTemplate#headForHeaders(java.lang.String, java.util.Map) */ - public HttpHeaders headForHeaders(String url, Map urlVariables) throws RestClientException { + public HttpHeaders headForHeaders(String url, Map urlVariables) { return this.restTemplate.headForHeaders(url, urlVariables); } @@ -291,7 +291,7 @@ public class TestRestTemplate { * @return all HTTP headers of that resource * @see RestTemplate#headForHeaders(java.net.URI) */ - public HttpHeaders headForHeaders(URI url) throws RestClientException { + public HttpHeaders headForHeaders(URI url) { return this.restTemplate.headForHeaders(applyRootUriIfNecessary(url)); } @@ -312,7 +312,7 @@ public class TestRestTemplate { * @see RestTemplate#postForLocation(java.lang.String, java.lang.Object, * java.lang.Object[]) */ - public URI postForLocation(String url, Object request, Object... urlVariables) throws RestClientException { + public URI postForLocation(String url, Object request, Object... urlVariables) { return this.restTemplate.postForLocation(url, request, urlVariables); } @@ -333,7 +333,7 @@ public class TestRestTemplate { * @see RestTemplate#postForLocation(java.lang.String, java.lang.Object, * java.util.Map) */ - public URI postForLocation(String url, Object request, Map urlVariables) throws RestClientException { + public URI postForLocation(String url, Object request, Map urlVariables) { return this.restTemplate.postForLocation(url, request, urlVariables); } @@ -350,7 +350,7 @@ public class TestRestTemplate { * @see HttpEntity * @see RestTemplate#postForLocation(java.net.URI, java.lang.Object) */ - public URI postForLocation(URI url, Object request) throws RestClientException { + public URI postForLocation(URI url, Object request) { return this.restTemplate.postForLocation(applyRootUriIfNecessary(url), request); } @@ -372,8 +372,7 @@ public class TestRestTemplate { * @see RestTemplate#postForObject(java.lang.String, java.lang.Object, * java.lang.Class, java.lang.Object[]) */ - public T postForObject(String url, Object request, Class responseType, Object... urlVariables) - throws RestClientException { + public T postForObject(String url, Object request, Class responseType, Object... urlVariables) { return this.restTemplate.postForObject(url, request, responseType, urlVariables); } @@ -395,8 +394,7 @@ public class TestRestTemplate { * @see RestTemplate#postForObject(java.lang.String, java.lang.Object, * java.lang.Class, java.util.Map) */ - public T postForObject(String url, Object request, Class responseType, Map urlVariables) - throws RestClientException { + public T postForObject(String url, Object request, Class responseType, Map urlVariables) { return this.restTemplate.postForObject(url, request, responseType, urlVariables); } @@ -414,7 +412,7 @@ public class TestRestTemplate { * @see HttpEntity * @see RestTemplate#postForObject(java.net.URI, java.lang.Object, java.lang.Class) */ - public T postForObject(URI url, Object request, Class responseType) throws RestClientException { + public T postForObject(URI url, Object request, Class responseType) { return this.restTemplate.postForObject(applyRootUriIfNecessary(url), request, responseType); } @@ -437,7 +435,7 @@ public class TestRestTemplate { * java.lang.Class, java.lang.Object[]) */ public ResponseEntity postForEntity(String url, Object request, Class responseType, - Object... urlVariables) throws RestClientException { + Object... urlVariables) { return this.restTemplate.postForEntity(url, request, responseType, urlVariables); } @@ -460,7 +458,7 @@ public class TestRestTemplate { * java.lang.Class, java.util.Map) */ public ResponseEntity postForEntity(String url, Object request, Class responseType, - Map urlVariables) throws RestClientException { + Map urlVariables) { return this.restTemplate.postForEntity(url, request, responseType, urlVariables); } @@ -478,8 +476,7 @@ public class TestRestTemplate { * @see HttpEntity * @see RestTemplate#postForEntity(java.net.URI, java.lang.Object, java.lang.Class) */ - public ResponseEntity postForEntity(URI url, Object request, Class responseType) - throws RestClientException { + public ResponseEntity postForEntity(URI url, Object request, Class responseType) { return this.restTemplate.postForEntity(applyRootUriIfNecessary(url), request, responseType); } @@ -499,7 +496,7 @@ public class TestRestTemplate { * @see HttpEntity * @see RestTemplate#put(java.lang.String, java.lang.Object, java.lang.Object[]) */ - public void put(String url, Object request, Object... urlVariables) throws RestClientException { + public void put(String url, Object request, Object... urlVariables) { this.restTemplate.put(url, request, urlVariables); } @@ -519,7 +516,7 @@ public class TestRestTemplate { * @see HttpEntity * @see RestTemplate#put(java.lang.String, java.lang.Object, java.util.Map) */ - public void put(String url, Object request, Map urlVariables) throws RestClientException { + public void put(String url, Object request, Map urlVariables) { this.restTemplate.put(url, request, urlVariables); } @@ -536,7 +533,7 @@ public class TestRestTemplate { * @see HttpEntity * @see RestTemplate#put(java.net.URI, java.lang.Object) */ - public void put(URI url, Object request) throws RestClientException { + public void put(URI url, Object request) { this.restTemplate.put(applyRootUriIfNecessary(url), request); } @@ -557,8 +554,7 @@ public class TestRestTemplate { * @since 1.4.4 * @see HttpEntity */ - public T patchForObject(String url, Object request, Class responseType, Object... uriVariables) - throws RestClientException { + public T patchForObject(String url, Object request, Class responseType, Object... uriVariables) { return this.restTemplate.patchForObject(url, request, responseType, uriVariables); } @@ -579,8 +575,7 @@ public class TestRestTemplate { * @since 1.4.4 * @see HttpEntity */ - public T patchForObject(String url, Object request, Class responseType, Map uriVariables) - throws RestClientException { + public T patchForObject(String url, Object request, Class responseType, Map uriVariables) { return this.restTemplate.patchForObject(url, request, responseType, uriVariables); } @@ -598,7 +593,7 @@ public class TestRestTemplate { * @since 1.4.4 * @see HttpEntity */ - public T patchForObject(URI url, Object request, Class responseType) throws RestClientException { + public T patchForObject(URI url, Object request, Class responseType) { return this.restTemplate.patchForObject(applyRootUriIfNecessary(url), request, responseType); } @@ -613,7 +608,7 @@ public class TestRestTemplate { * @param urlVariables the variables to expand in the template * @see RestTemplate#delete(java.lang.String, java.lang.Object[]) */ - public void delete(String url, Object... urlVariables) throws RestClientException { + public void delete(String url, Object... urlVariables) { this.restTemplate.delete(url, urlVariables); } @@ -628,7 +623,7 @@ public class TestRestTemplate { * @param urlVariables the variables to expand the template * @see RestTemplate#delete(java.lang.String, java.util.Map) */ - public void delete(String url, Map urlVariables) throws RestClientException { + public void delete(String url, Map urlVariables) { this.restTemplate.delete(url, urlVariables); } @@ -640,7 +635,7 @@ public class TestRestTemplate { * @param url the URL * @see RestTemplate#delete(java.net.URI) */ - public void delete(URI url) throws RestClientException { + public void delete(URI url) { this.restTemplate.delete(applyRootUriIfNecessary(url)); } @@ -653,7 +648,7 @@ public class TestRestTemplate { * @return the value of the allow header * @see RestTemplate#optionsForAllow(java.lang.String, java.lang.Object[]) */ - public Set optionsForAllow(String url, Object... urlVariables) throws RestClientException { + public Set optionsForAllow(String url, Object... urlVariables) { return this.restTemplate.optionsForAllow(url, urlVariables); } @@ -666,7 +661,7 @@ public class TestRestTemplate { * @return the value of the allow header * @see RestTemplate#optionsForAllow(java.lang.String, java.util.Map) */ - public Set optionsForAllow(String url, Map urlVariables) throws RestClientException { + public Set optionsForAllow(String url, Map urlVariables) { return this.restTemplate.optionsForAllow(url, urlVariables); } @@ -676,7 +671,7 @@ public class TestRestTemplate { * @return the value of the allow header * @see RestTemplate#optionsForAllow(java.net.URI) */ - public Set optionsForAllow(URI url) throws RestClientException { + public Set optionsForAllow(URI url) { return this.restTemplate.optionsForAllow(applyRootUriIfNecessary(url)); } @@ -697,7 +692,7 @@ public class TestRestTemplate { * org.springframework.http.HttpEntity, java.lang.Class, java.lang.Object[]) */ public ResponseEntity exchange(String url, HttpMethod method, HttpEntity requestEntity, - Class responseType, Object... urlVariables) throws RestClientException { + Class responseType, Object... urlVariables) { return this.restTemplate.exchange(url, method, requestEntity, responseType, urlVariables); } @@ -718,7 +713,7 @@ public class TestRestTemplate { * org.springframework.http.HttpEntity, java.lang.Class, java.util.Map) */ public ResponseEntity exchange(String url, HttpMethod method, HttpEntity requestEntity, - Class responseType, Map urlVariables) throws RestClientException { + Class responseType, Map urlVariables) { return this.restTemplate.exchange(url, method, requestEntity, responseType, urlVariables); } @@ -736,7 +731,7 @@ public class TestRestTemplate { * org.springframework.http.HttpEntity, java.lang.Class) */ public ResponseEntity exchange(URI url, HttpMethod method, HttpEntity requestEntity, - Class responseType) throws RestClientException { + Class responseType) { return this.restTemplate.exchange(applyRootUriIfNecessary(url), method, requestEntity, responseType); } @@ -761,7 +756,7 @@ public class TestRestTemplate { * org.springframework.core.ParameterizedTypeReference, java.lang.Object[]) */ public ResponseEntity exchange(String url, HttpMethod method, HttpEntity requestEntity, - ParameterizedTypeReference responseType, Object... urlVariables) throws RestClientException { + ParameterizedTypeReference responseType, Object... urlVariables) { return this.restTemplate.exchange(url, method, requestEntity, responseType, urlVariables); } @@ -786,7 +781,7 @@ public class TestRestTemplate { * org.springframework.core.ParameterizedTypeReference, java.util.Map) */ public ResponseEntity exchange(String url, HttpMethod method, HttpEntity requestEntity, - ParameterizedTypeReference responseType, Map urlVariables) throws RestClientException { + ParameterizedTypeReference responseType, Map urlVariables) { return this.restTemplate.exchange(url, method, requestEntity, responseType, urlVariables); } @@ -810,7 +805,7 @@ public class TestRestTemplate { * org.springframework.core.ParameterizedTypeReference) */ public ResponseEntity exchange(URI url, HttpMethod method, HttpEntity requestEntity, - ParameterizedTypeReference responseType) throws RestClientException { + ParameterizedTypeReference responseType) { return this.restTemplate.exchange(applyRootUriIfNecessary(url), method, requestEntity, responseType); } @@ -828,8 +823,7 @@ public class TestRestTemplate { * @return the response as entity * @see RestTemplate#exchange(org.springframework.http.RequestEntity, java.lang.Class) */ - public ResponseEntity exchange(RequestEntity requestEntity, Class responseType) - throws RestClientException { + public ResponseEntity exchange(RequestEntity requestEntity, Class responseType) { return this.restTemplate.exchange(createRequestEntityWithRootAppliedUri(requestEntity), responseType); } @@ -849,8 +843,7 @@ public class TestRestTemplate { * @see RestTemplate#exchange(org.springframework.http.RequestEntity, * org.springframework.core.ParameterizedTypeReference) */ - public ResponseEntity exchange(RequestEntity requestEntity, ParameterizedTypeReference responseType) - throws RestClientException { + public ResponseEntity exchange(RequestEntity requestEntity, ParameterizedTypeReference responseType) { return this.restTemplate.exchange(createRequestEntityWithRootAppliedUri(requestEntity), responseType); } @@ -871,7 +864,7 @@ public class TestRestTemplate { * org.springframework.web.client.ResponseExtractor, java.lang.Object[]) */ public T execute(String url, HttpMethod method, RequestCallback requestCallback, - ResponseExtractor responseExtractor, Object... urlVariables) throws RestClientException { + ResponseExtractor responseExtractor, Object... urlVariables) { return this.restTemplate.execute(url, method, requestCallback, responseExtractor, urlVariables); } @@ -892,7 +885,7 @@ public class TestRestTemplate { * org.springframework.web.client.ResponseExtractor, java.util.Map) */ public T execute(String url, HttpMethod method, RequestCallback requestCallback, - ResponseExtractor responseExtractor, Map urlVariables) throws RestClientException { + ResponseExtractor responseExtractor, Map urlVariables) { return this.restTemplate.execute(url, method, requestCallback, responseExtractor, urlVariables); } @@ -910,7 +903,7 @@ public class TestRestTemplate { * org.springframework.web.client.ResponseExtractor) */ public T execute(URI url, HttpMethod method, RequestCallback requestCallback, - ResponseExtractor responseExtractor) throws RestClientException { + ResponseExtractor responseExtractor) { return this.restTemplate.execute(applyRootUriIfNecessary(url), method, requestCallback, responseExtractor); }