Skip to main content

Mock REST Client Overview

The MockRestClient class is used for performing serverless unit testing of @Rest-annotated and @Remote-annotated classes.

The MockRestClient itself extends from RestClient providing it with the rich feature set of that API.

The following shows a simple example of invoking a PUT method on a simple REST interface and asserting the correct status code and response body:

public class MockTest {

// A simple bean with one field.
public static class MyBean {
public int foo = 1;
}

// Our REST resource to test.
// Simply echos the response.
@Rest
public static class EchoRest implements BasicRestServlet {

@RestPut
public MyBean echo(@Content MyBean bean) {
return bean;
}
}

// Our JUnit test.
@Test
public void testEcho() throws Exception {

MyBean myBean = new MyBean();

// Do a round-trip on the bean through the REST interface
myBean = MockRestClient
.create(EchoRest.class)
.json5()
.build()
.put("/echo", myBean)
.run()
.assertStatus().is(200)
.assertContent().is("{foo:1}")
.getContent().as(MyBean.class);

assertEquals(1, myBean.foo);
}
}

Breaking apart the fluent method call above will help you understand how this works.

@Test
public void testEcho() throws Exception {

// Instantiate our mock client.
MockRestClient client = MockRestClient
.create(EchoRest.class)
.json5()
.build();

// Create a request.
RestRequest req = client.put("/echo", myBean);

// Execute it (by calling RestCallHandler.service(...) and then returning the response object).
RestResponse res = req.run();

// Run assertion tests on the results.
res.assertStatus().is(200);
res.assertContent().is("'foo'");

myBean = res.getContent().as(MyBean.class);
}

The concept of the design is simple. The MockRestClient class is used to create instances of MockServletRequest and MockServletResponse which are passed directly to the call handler on the resource class RestOpInvoker.invoke(RestOpSession). In effect, you're fully testing your REST API as if it were running in a live servlet container, yet not actually having to run in a servlet container. All aspects of the client and server side code are tested, yet no servlet container is required. The actual over-the-wire transmission is the only aspect being bypassed. The create(Object) method can take in either Class objects or pre-instantiated beans. The latter is particularly useful for testing REST APIs written as Spring beans.

@RunWith(SpringRunner.class)
@ContextConfiguration(classes = {MyApp.class})
@SpringBootTest
public class MockTest {

@Autowired
EchoRest echoRest;

MockRestClient client;

@Before
public void setup() {
// Instantiate our mock client.
client = MockRestClient
.create(echoRest)
.json5()
.build();
}

// Our JUnit test.
@Test
public void testEcho() throws Exception {

MyBean myBean = new MyBean();

// Do a round-trip on the bean through the REST interface
myBean = client
.put("/echo", myBean)
.run()
.assertStatus().is(200)
.assertContent().is("{foo:1}")
.getContent().as(MyBean.class);

assertEquals(1, myBean.foo);
}
}

The MockRestRequest object has convenience methods provided to allow you to set properties directly on the underlying HttpServletRequest object. The following example shows how this can be used to directly set roles on the request object to perform security testing.

Example
@Rest(roleGuard="ADMIN")
public class A {
@RestGet
public String get() {
return "OK";
}
}

@Test
public void mytest() throws Exception {
MockRestClient client = MockRestClient.build(A.class);

// Admin user should get 200 but anyone else should get 403-Unauthorized.
client.get().roles("ADMIN").run().assertStatus().is(200);
client.get().roles("USER").run().assertStatus().is(403);
}

The MockRestClient class has a debug mode that will cause your HTTP requests and responses to be sent to the console:

MockRestClient client = MockRestClient
.create(MyRest.class)
.debug()
.json5()
.build();

The MockRestClient class can also be used for testing of Remote-annotated interfaces against @Rest-annotated resources.

Example
// Our remote resource to test.
@Remote
public interface MyRemoteInterface {

@RemoteGet("/echoQuery")
public int echoQuery(@Query(name="id") int id);
}

// Our mocked-up REST interface to test against.
@Rest
public class MyRest {

@RestGet
public int echoQuery(@Query("id") String id) {
return id;
}
}

@Test
public void testProxy() {
MyRemoteInterface mri = MockRestClient
.create(MyRest.class)
.json()
.build()
.getRemote(MyRemoteInterface.class);

assertEquals(123, mri.echoQuery(123));
}