{8.2.0-new} MockRestClient

The {@link oajr.mock2.MockRestClient} class is used for performing serverless unit testing of {@link oajr.annotation.Rest @Rest}-annotated and {@link oaj.http.remote.Remote @Remote}-annotated classes.

The {@link oajr.mock2.MockRestClient} itself extends from {@link oajr.client.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 BasicJsonRest { @RestMethod public MyBean putEcho(@Body 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) .simpleJson() .build() .put("/echo", myBean) .run() .assertStatus().is(200) .assertBody().is("{foo:1}") .getBody().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) .simpleJson() .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.assertBody().is("'foo'"); myBean = res.getBody().as(MyBean.class); }

The concept of the design is simple. The {@link oajr.mock2.MockRestClient} class is used to create instances of {@link oajr.mock2.MockServletRequest} and {@link oajr.mock2.MockServletResponse} which are passed directly to the call handler on the resource class {@link oajr.RestCallHandler#execute(HttpServletRequest,HttpServletResponse)}. 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) .simpleJson() .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) .assertBody().is("{foo:1}") .getBody().as(MyBean.class); assertEquals(1, myBean.foo); } }


The {@link oajr.mock2.MockRestRequest} object has convenience methods provided to allow you to set properties directly on the underlying {@link javax.servlet.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 { @RestMethod 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 {@link oajr.mock2.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() .simpleJson() .build();


The {@link oajr.mock2.MockRestClient} class can also be used for testing of {@link oaj.http.remote.Remote}-annotated interfaces against {@link oajr.annotation.Rest @Rest}-annotated resources.

Example:

// Our remote resource to test. @Remote public interface MyRemoteInterface { @RemoteMethod(method="GET", path="/echoQuery") public int echoQuery(@Query(name="id") int id); } // Our mocked-up REST interface to test against. @Rest public class MyRest { @RestMethod(name=GET, path="/echoQuery") 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)); }