NG Mock REST Client
The juneau-rest-mock module provides two ways to test code that uses the NG
RestClient without a network:
| Class | Use it to test |
|---|---|
org.apache.juneau.rest.mock.MockRestClient | A @Rest resource, in-process. The request is dispatched straight to the resource's RestContext. |
org.apache.juneau.rest.mock.MockHttpTransport | Client code (a RestClient or @Remote proxy) against canned responses that you define. |
See the guide: Test an endpoint with MockRestClient
The classic mock client is documented in Mock REST Client Overview.
MockRestClient (test a @Rest resource)
MockRestClient wraps a RestClient whose transport calls the resource directly. The argument is a
@Rest bean instance or class. Request paths are relative to the resource's @Rest(path), so for a
PetResource annotated @Rest(path="/pets"), mock.get("/1") reaches /pets/1. A path of /pets/1 would
look for /pets/pets/1 and return a 404.
try (MockRestClient mock = MockRestClient.create(PetResource.class);
var resp = mock.get("/1").run()) {
resp.assertThat().isOk().body().contains("Fido");
}
The verb methods (get, post, put, patch, delete, head, request) return the same
RestRequest as a real client, so assertions,
interceptors and typed bodies all work. getClient() exposes the
underlying RestClient, for example to create a @Remote proxy:
PetApi api = mock.getClient().remote(PetApi.class);
Builder
MockRestClient mock = MockRestClient.builder(new PetResource())
.contextPath("/app")
.defaultParser(Json5Parser.create().build())
.build();
| Method | Purpose |
|---|---|
contextPath(String) | Simulates a servlet context path. The root URL becomes http://localhost + context path + servlet path. |
overridingBeanStore(BeanStore) | Supplies beans to the resource. Disables the per-class RestContext cache so your beans are used. |
defaultParser(Parser) | Parser for body().as(...). |
noTrace() | Sends No-Trace: true on every request; see below. |
Without an overriding bean store, the RestContext is created once per resource class and reused
across tests, so mock clients are cheap to create.
Keeping expected-error traces out of the log
A test that asserts a 404, 405 or 415 normally makes the server log a stack trace for an outcome the test expects.
Send No-Trace: true to keep the trace off the log record while the one-line access record (status, method, path)
is still logged. Use noTrace() on the builder for every call from that client:
try (MockRestClient mock = MockRestClient.builder(PetResource.class).noTrace().build();
var resp = mock.get("/1/missing").run()) {
resp.assertStatus(404);
}
or on a single request, which leaves the other calls from the same client unchanged:
try (var resp = mock.get("/1/missing").noTrace().run()) {
resp.assertStatus(404);
}
No-Trace is opt-in only: ignoreErrors() and the other builder options do not turn it on. See
Logging / Debugging
for what the server does with the header.
Redirect and URL-policy behavior matches the real client; see NG Client Security.
MockHttpTransport (test client code)
MockHttpTransport is an HttpTransport with routes you define. Plug it into a real RestClient:
var transport = MockHttpTransport.builder()
.on("GET", "/pets/1", req -> TransportResponse.builder()
.statusCode(200)
.header("Content-Type", "application/json")
.body(new ByteArrayInputStream("{\"name\":\"Fido\"}".getBytes(UTF_8)))
.build())
.on("POST", "/pets", req -> TransportResponse.builder().statusCode(201).build())
.recordRequests()
.build();
var client = RestClient.builder().transport(transport).rootUrl("http://mock").build();
try (var resp = client.get("/pets/1").run()) {
resp.assertOk();
}
assertEquals(1, transport.getRecordedRequests().size());
on(method, path, handler)matches the HTTP method and the exact path. Anullmethod or path matches anything.fallback(handler)handles unmatched requests. Without one, unmatched requests get a404with the bodyNo mock route matched: METHOD path.recordRequests()keeps everyTransportRequest; read them withgetRecordedRequests()and reset withclearRecordedRequests().- A handler can throw
TransportExceptionto simulate a network failure. MockHttpTransport.of(status, body)is a one-liner that always returns the same response.
The transport reports supportsUrlPolicy() == true and follows redirects with the same
re-validation loop as the production transports, so @Remote tests exercise the SSRF guard too.
MockPathResolver
MockPathResolver resolves an incoming URL into the artifacts an HttpServletRequest would report:
getTarget(), getContextPath(), getServletPath(), getRemainder(), getURI(), and getError().
Its constructor takes (target, contextPath, servletPath, pathToResolve, pathVars); {name} tokens in
the context and servlet paths are filled from pathVars, and a null target defaults to
http://localhost.
It is used by the classic org.apache.juneau.rest.mock.classic.MockRestClient. The NG
MockRestClient does not use it; it derives its root URL from contextPath and the resource's servlet
path. You only need MockPathResolver directly when writing your own classic-style mock harness.
The classic MockRestClient supplies its own connection manager, which the classic SSRF guard cannot
pin, so its getRemote(...) proxies need allowPrivateUrls(true) on the builder (see
NG Client Security).
See also
- Test an endpoint with MockRestClient: a guided walkthrough.
- Next-Generation REST Client
- juneau-rest-mock
- Mock REST Client Overview (classic)