5.2 KiB
rest-client-test
Companion module for ankurm.com - testing Spring REST clients on Spring
Boot 4.1.1 with @RestClientTest and MockRestServiceServer: a RestClient-based client, a
RestTemplate-based client, a declarative @HttpExchange interface client, an error-path test,
and @MockitoBean standing in for a plain collaborator bean now that @MockBean is gone.
Versions actually used here
| Component | Version | Verified against |
|---|---|---|
| Spring Boot | 4.1.1 | spring-boot-starter-parent POM, Maven Central |
| Spring Framework | 7.0.9 | resolved transitively, confirmed via mvn dependency:tree |
| JDK | 25 (Temurin 25.0.4.1+1) | java -version in this sandbox |
| JUnit | 6.0.3 | resolved transitively |
| Jackson | 3.1.5, groupId tools.jackson.core |
resolved transitively, confirmed via mvn dependency:tree and by unzipping the jar |
The module-naming trap, reconfirmed
@RestClientTest and MockRestServiceServer's auto-configuration now live in
spring-boot-restclient-test (org.springframework.boot.restclient.test.autoconfigure.RestClientTest),
not in spring-boot-resttestclient - that second module backs the newer RestTestClient type used
in the rest-test-client module instead. Confirmed by unzipping both jars
and listing their classes; the names are one letter apart and Maven Central's search box will
happily suggest the wrong one.
RestTemplateBuilder moved too, from org.springframework.boot.web.client (Boot 3.x) to
org.springframework.boot.restclient.RestTemplateBuilder - same module, spring-boot-restclient,
as RestClient.Builder's auto-configuration. A Boot 3 import of RestTemplateBuilder fails to
compile on Boot 4.1 with no hint beyond "package does not exist."
The bigger surprise: Jackson 3 by default
mvn dependency:tree resolves tools.jackson.core:jackson-databind:3.1.5, not
com.fasterxml.jackson.core:jackson-databind. Spring Boot 4.1's spring-boot-starter-jackson
pulls in Jackson 3, whose ObjectMapper lives at tools.jackson.databind.ObjectMapper - a
different package entirely, not just a version bump. com.fasterxml.jackson.core:jackson-annotations
is still on the classpath (so @JsonProperty etc. keep their old import), but jackson-databind
and jackson-core are the new tools.jackson.* artifacts. Every test class in this module imports
tools.jackson.databind.ObjectMapper, not the classic one - this bit every test file on the first
compile attempt here. See the Jackson 3 post on this blog for the full
migration story.
Quickstart
./scripts/run-all.sh
Runs the full suite and regenerates every file in docs/output/.
Test classes
| Class | What it proves |
|---|---|
RestClientEmployeeTest |
@RestClientTest(EmployeeClient.class) + MockRestServiceServer, with @MockitoBean replacing the collaborator EmployeeAuditLogger |
RestTemplateEmployeeTest |
The same job on RestTemplate, and the one case where a relative requestTo() still works against an absolute root URI |
HttpInterfaceClientTest |
@RestClientTest(components = AppConfig.class) wiring a declarative @HttpExchange interface client through the mock |
ErrorScenarioTest |
A 404 from MockRestServiceServer surfacing as HttpClientErrorException.NotFound |
Captured output
| File | From |
|---|---|
00-full-test-run.txt |
mvn test, all 4 classes, green |
01-restclient-basic-fetch.txt |
RestClientEmployeeTest |
02-resttemplate-same-mocking-code.txt |
RestTemplateEmployeeTest |
03-404-throws-notfound.txt |
ErrorScenarioTest |
04-http-interface-client.txt |
HttpInterfaceClientTest |
05-restclient-relative-requestto-fails.txt |
A scratch test (not committed) reproducing the real AssertionError when requestTo() is written relative against a RestClient built with an absolute baseUrl |
Why #01 and #05 use an absolute requestTo() but #02 does not
EmployeeClient builds its RestClient with RestClient.Builder.baseUrl("http://hr-api.example.com").
EmployeeTemplateClient builds its RestTemplate with RestTemplateBuilder.rootUri(...) instead.
Spring Boot's MockRestServiceServerAutoConfiguration detects a RestTemplate built with a root
URI and binds it through RootUriRequestExpectationManager
(org.springframework.boot.restclient.test.RootUriRequestExpectationManager), which strips the
root URI before matching - so requestTo("/employees/2") still works. There is no equivalent for
RestClient.Builder.baseUrl(...): a RestClient test has to match the full absolute URI, as #05's
captured failure shows. This is covered in depth in the published post.