82 lines
5.2 KiB
Markdown
82 lines
5.2 KiB
Markdown
# rest-client-test
|
|
|
|
Companion module for [ankurm.com](https://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`](../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](https://ankurm.com) on this blog for the full
|
|
migration story.
|
|
|
|
## Quickstart
|
|
|
|
```bash
|
|
./scripts/run-all.sh
|
|
```
|
|
|
|
Runs the full suite and regenerates every file in `docs/output/`.
|
|
|
|
## Test classes
|
|
|
|
| Class | What it proves |
|
|
|---|---|
|
|
| [`RestClientEmployeeTest`](src/test/java/com/ankurm/restclienttest/RestClientEmployeeTest.java) | `@RestClientTest(EmployeeClient.class)` + `MockRestServiceServer`, with `@MockitoBean` replacing the collaborator `EmployeeAuditLogger` |
|
|
| [`RestTemplateEmployeeTest`](src/test/java/com/ankurm/restclienttest/RestTemplateEmployeeTest.java) | The same job on `RestTemplate`, and the one case where a *relative* `requestTo()` still works against an absolute root URI |
|
|
| [`HttpInterfaceClientTest`](src/test/java/com/ankurm/restclienttest/HttpInterfaceClientTest.java) | `@RestClientTest(components = AppConfig.class)` wiring a declarative `@HttpExchange` interface client through the mock |
|
|
| [`ErrorScenarioTest`](src/test/java/com/ankurm/restclienttest/ErrorScenarioTest.java) | A 404 from `MockRestServiceServer` surfacing as `HttpClientErrorException.NotFound` |
|
|
|
|
## Captured output
|
|
|
|
| File | From |
|
|
|---|---|
|
|
| [`00-full-test-run.txt`](docs/output/00-full-test-run.txt) | `mvn test`, all 4 classes, green |
|
|
| [`01-restclient-basic-fetch.txt`](docs/output/01-restclient-basic-fetch.txt) | `RestClientEmployeeTest` |
|
|
| [`02-resttemplate-same-mocking-code.txt`](docs/output/02-resttemplate-same-mocking-code.txt) | `RestTemplateEmployeeTest` |
|
|
| [`03-404-throws-notfound.txt`](docs/output/03-404-throws-notfound.txt) | `ErrorScenarioTest` |
|
|
| [`04-http-interface-client.txt`](docs/output/04-http-interface-client.txt) | `HttpInterfaceClientTest` |
|
|
| [`05-restclient-relative-requestto-fails.txt`](docs/output/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.
|