The {@link oajr.mock.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.mock.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 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 {@link oajr.mock.MockRestClient} class is used to create instances of {@link oajr.mock.MockServletRequest}
and {@link oajr.mock.MockServletResponse} which are passed directly to the call handler on the resource class {@link oajr.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 {@link oajr.mock.MockRestRequest} object has convenience methods provided to allow you to set properties
directly on the underlying {@link jakarta.servlet.http.HttpServletRequest} object. The following example shows how
this can be used to directly set roles on the request object to perform security testing.
| @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 {@link oajr.mock.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 {@link oajr.mock.MockRestClient} class can also be used for testing of {@link oaj.http.remote.Remote}-annotated
interfaces against {@link oajr.annotation.Rest @Rest}-annotated resources.
| // 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));
| }