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,POSTPATCH), 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();