MockRest

The {@link oajr.mock2.MockRest} class is used for performing serverless unit testing of {@link oajr.annotation.Rest @Rest}-annotated classes. These include both parent resource classes that extend from {@link oajr.RestServlet} and child resources that do not.

The API consists of the following classes:

- {@link oajr.mock2}
  - {@link oajr.mock2.MockRest}
    The API for instantiating mocks of REST resource classes.
  - {@link oajr.mock2.MockServletRequest}
    An implementation of {@link javax.servlet.http.HttpServletRequest} with additional convenience methods for building requests.
  - {@link oajr.mock2.MockServletResponse}
    An implementation of {@link javax.servlet.http.HttpServletRequest} with additional convenience methods for testing responses.

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 { // Our REST resource to test. @Rest( serializers=SimpleJsonSerializer.class, parsers=JsonParser.class ) public static class EchoRest { @RestMethod( name=PUT, path="/echo" ) public String echo(@Body String body) { return body; } } // Our JUnit test. @Test public void testEcho() throws Exception { MockRest mr = MockRest.build(EchoRest.class); mr .put("/echo", "'foo'") .execute() .assertStatus(200) .assertBody("'foo'"); } }

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

@Test public void testEcho() throws Exception { // Instantiate our mock. MockRest mr = MockRest.build(EchoRest.class); // Create a request. MockServletRequest req = mr.put("/echo", "'foo'"); // Execute it (by calling RestCallHandler.service(...) and then returning the response object). MockServletResponse res = req.execute(); // Run assertion tests on the results. res.assertStatus(200); res.assertBody("'foo'"); }

The concept of the design is simple. The {@link oajr.mock2.MockRest} 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#service(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.

The create(Object) method can take in either Class objects or pre-instantiated beans. The latter is particularly useful for testing Spring beans.

By default, the {@link oajr.mock2.MockRest} class specifies the following request headers:

Accept: application/json+simple Content-Type: application/json

The reason for using "application/json+simple" as the default is that it significantly simplifies testing by allowing you to compare response content with simple Java strings without having to escape lots of quotes:

// Using Simple JSON mr.assertBody("{foo:'bar':baz:123}"); // Using normal JSON mr.assertBody("{\"foo\":\"bar\",\"baz\":123}");

Other media types headers can be specified via any of the following methods:

- {@link oajr.mock2.MockRest#build(Object,Marshall) build(Object,Marshall)} - Use media types defined on a marshall.
- {@link oajr.mock2.MockRest#build(Object,Serializer,Parser) build(Object,Serializer,Parser)} - Use media types defined on a serializer and parser.
- {@link oajr.mock2.MockRest.Builder#accept(String) accept(String)} - Explicitly set the Accept header.
- {@link oajr.mock2.MockRest.Builder#contentType(String) contentType(String)} - Explicitly set the Content-Type header.

Various other convenience methods for common media types are also provided.

The following examples are functionally equivalent for specifying XML serialization:

MockRest mr; mr = MockRest.build(EchoRest.class, Xml.DEFAULT); mr = MockRest.build(EchoRest.class, XmlSerializer.DEFAULT, XmlParser.DEFAULT); mr = MockRest.create(EchoRest.class).marshall(Xml.DEFAULT).build(); mr = MockRest.create(EchoRest.class).serializer(XmlSerializer.DEFAULT).parser(XmlParser.DEFAULT).build(); mr = MockRest.create(EchoRest.class).accept("text/xml").contentType("text/xml").build(); mr = MockRest.create(EchoRest.class).xml().build();

The {@link oajr.mock2.MockRest} class provides the following methods for creating requests:

- {@link oajr.mock2.MockRest}
  - {@link oajr.mock2.MockRest#request(String,String) request(String,String)}
  - {@link oajr.mock2.MockRest#request(String,String,Object) request(String,String,Object)}
  - {@link oajr.mock2.MockRest#get(String) get(String)}
  - {@link oajr.mock2.MockRest#put(String,Object) put(String,Object)}
  - {@link oajr.mock2.MockRest#post(String,Object) post(String,Object)}
  - {@link oajr.mock2.MockRest#delete(String) delete(String)}
  - {@link oajr.mock2.MockRest#patch(String,Object) patch(String,Object)}
  - {@link oajr.mock2.MockRest#options(String) options(String)}

For HTTP methods that pass a request body (i.e. PUT,POST PATCH), the body object can be any of the following types:

- byte[]
- {@link java.io.Reader}
- {@link java.io.InputStream}
- {@link java.lang.CharSequence}

All other body object types are converted to strings using the toString() method.

A common tactic is to override a bean's toString() method to return Simple JSON so that instances can be passed to the methods above.

public class MyBean { ... @Override public String toString() { SimpleJson.DEFAULT.toString(this); } }

The {@link oajr.mock2.MockServletRequest} class provides default implementations for all the methods defined on the {@link javax.servlet.http.HttpServletRequest} in addition to many convenience methods.

The following fluent convenience methods are provided for setting common Accept and Content-Type headers.

- {@link oajr.mock2.MockServletRequest}
  - {@link oajr.mock2.MockServletRequest#json() json()}
  - {@link oajr.mock2.MockServletRequest#xml() xml()}
  - {@link oajr.mock2.MockServletRequest#html() html()}
  - {@link oajr.mock2.MockServletRequest#plainText() plainText()}
  - {@link oajr.mock2.MockServletRequest#msgpack() msgpack()}
  - {@link oajr.mock2.MockServletRequest#uon() uon()}
  - {@link oajr.mock2.MockServletRequest#urlEnc() urlEnc()}
  - {@link oajr.mock2.MockServletRequest#yaml() yaml()}

The following fluent convenience methods are provided for building up your request.

- {@link oajr.mock2.MockServletRequest}
  - {@link oajr.mock2.MockServletRequest#header(String,Object) header(String,Object)}
  - {@link oajr.mock2.MockServletRequest#query(String,Object) query(String,Object}}
  - {@link oajr.mock2.MockServletRequest#formData(String,Object) formData(String,Object)}
  - {@link oajr.mock2.MockServletRequest#attribute(String,Object) attribute(String,Object)}
  - {@link oajr.mock2.MockServletRequest#body(Object) body(Object)}

Fluent setters are provided for all common request headers:

- {@link oajr.mock2.MockServletRequest}
  - {@link oajr.mock2.MockServletRequest#accept(Object) accept(Object)}
  - {@link oajr.mock2.MockServletRequest#acceptCharset(Object) acceptCharset(Object)}
  - {@link oajr.mock2.MockServletRequest#acceptEncoding(Object) acceptEncoding(Object)}
  - {@link oajr.mock2.MockServletRequest#acceptLanguage(Object) acceptLanguage(Object)}
  - ...

The {@link oajr.mock2.MockServletResponse} class provides default implementations for all the methods defined on the {@link javax.servlet.http.HttpServletResponse} in addition to many convenience methods.

- {@link oajr.mock2.MockServletResponse}
  - {@link oajr.mock2.MockServletResponse#getBody() getBody()}
  - {@link oajr.mock2.MockServletResponse#getBodyAsString() getBodyAsString()}
  - {@link oajr.mock2.MockServletResponse#assertStatus(int) assertStatus(int)}
  - {@link oajr.mock2.MockServletResponse#assertBody(String) assertBody(String)}
  - {@link oajr.mock2.MockServletResponse#assertBodyContains(String...) assertBodyContains(String...)}
  - {@link oajr.mock2.MockServletResponse#assertBodyMatches(String) assertBodyMatches(String)}
  - {@link oajr.mock2.MockServletResponse#assertBodyMatchesRE(String) assertBodyMatchesRE(String)}
  - {@link oajr.mock2.MockServletResponse#assertHeader(String,String) assertHeader(String,String)}
  - {@link oajr.mock2.MockServletResponse#assertHeaderContains(String,String...) assertHeaderContains(String,String...)}

The {@link oajr.mock2.MockRest} class has a debug mode that will cause your HTTP requests and responses to be sent to the console:

MockRest mr = MockRest .create(MyRest.class) .debug() .simpleJson() .build();