| <!-- |
| /*************************************************************************************************************************** |
| * Licensed to the Apache Software Foundation (ASF) under one or more contributor license agreements. See the NOTICE file |
| * distributed with this work for additional information regarding copyright ownership. The ASF licenses this file |
| * to you under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance |
| * with the License. You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an |
| * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the |
| * specific language governing permissions and limitations under the License. |
| ***************************************************************************************************************************/ |
| --> |
| |
| MockRest |
| |
| <p> |
| The {@link oajr.mock2.MockRest} class is used for performing serverless unit testing of {@link oajr.annotation.RestResource @RestResource}-annotated |
| classes. These include both parent resource classes that extend from {@link oajr.RestServlet} and child resources that do not. |
| </p> |
| <p> |
| The API consists of the following classes: |
| </p> |
| <ul class='javatree'> |
| <li class='jp'>{@link oajr.mock2} |
| <ul> |
| <li class='jc'>{@link oajr.mock2.MockRest} |
| <br>The API for instantiating mocks of REST resource classes. |
| <li class='jc'>{@link oajr.mock2.MockServletRequest} |
| <br>An implementation of {@link javax.servlet.http.HttpServletRequest} with additional convenience methods for building requests. |
| <li class='jc'>{@link oajr.mock2.MockServletResponse} |
| <br>An implementation of {@link javax.servlet.http.HttpServletRequest} with additional convenience methods for testing responses. |
| </ul> |
| </ul> |
| <p> |
| 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: |
| </p> |
| <p class='bpcode w800'> |
| <jk>public class</jk> MockTest { |
| |
| <jc>// Our REST resource to test.</jc> |
| <ja>@RestResource</ja>( |
| serializers=SimpleJsonSerializer.<jk>class</jk>, |
| parsers=JsonParser.<jk>class</jk> |
| ) |
| <jk>public static class</jk> EchoRest { |
| |
| <ja>@RestMethod</ja>( |
| name=<jsf>PUT</jsf>, |
| path=<js>"/echo"</js> |
| ) |
| <jk>public</jk> String echo(<ja>@Body</ja> String body) { |
| <jk>return</jk> body; |
| } |
| } |
| |
| <jc>// Our JUnit test.</jc> |
| <ja>@Test</ja> |
| <jk>public void</jk> testEcho() <jk>throws</jk> Exception { |
| |
| MockRest mr = MockRest.<jsm>build</jsm>(EchoRest.<jk>class</jk>); |
| |
| mr |
| .put(<js>"/echo"</js>, <js>"'foo'"</js>) |
| .execute() |
| .assertStatus(200) |
| .assertBody(<js>"'foo'"</js>); |
| } |
| } |
| </p> |
| <p> |
| Breaking apart the fluent method call above will help you understand how this works. |
| </p> |
| <p class='bpcode w800'> |
| <ja>@Test</ja> |
| <jk>public void</jk> testEcho() <jk>throws</jk> Exception { |
| |
| <jc>// Instantiate our mock.</jc> |
| MockRest mr = MockRest.<jsm>build</jsm>(EchoRest.<jk>class</jk>); |
| |
| <jc>// Create a request.</jc> |
| MockServletRequest req = mr.put(<js>"/echo"</js>, <js>"'foo'"</js>); |
| |
| <jc>// Execute it (by calling RestCallHandler.service(...) and then returning the response object).</jc> |
| MockServletResponse res = req.execute(); |
| |
| <jc>// Run assertion tests on the results.</jc> |
| res.assertStatus(200); |
| res.assertBody(<js>"'foo'"</js>); |
| } |
| </p> |
| <p> |
| 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. |
| </p> |
| <p> |
| The <c>create(Object)</c> method can take in either <c>Class</c> objects or pre-instantiated beans. |
| The latter is particularly useful for testing Spring beans. |
| </p> |
| <hr> |
| <p> |
| By default, the {@link oajr.mock2.MockRest} class specifies the following request headers: |
| </p> |
| <p class='bpcode w800'> |
| Accept: application/json+simple |
| Content-Type: application/json |
| </p> |
| <p> |
| The reason for using <js>"application/json+simple"</js> 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: |
| </p> |
| <p class='bpcode w800'> |
| <jc>// Using Simple JSON</jc> |
| mr.assertBody(<js>"{foo:'bar':baz:123}"</js>); |
| |
| <jc>// Using normal JSON</jc> |
| mr.assertBody(<js>"{\"foo\":\"bar\",\"baz\":123}"</js>); |
| </p> |
| <p> |
| Other media types headers can be specified via any of the following methods: |
| </p> |
| <ul class='javatree'> |
| <li class='jm'>{@link oajr.mock2.MockRest#build(Object,Marshall) build(Object,Marshall)} - Use media types defined on a marshall. |
| <li class='jm'>{@link oajr.mock2.MockRest#build(Object,Serializer,Parser) build(Object,Serializer,Parser)} - Use media types defined on a serializer and parser. |
| <li class='jm'>{@link oajr.mock2.MockRest.Builder#accept(String) accept(String)} - Explicitly set the <c>Accept</c> header. |
| <li class='jm'>{@link oajr.mock2.MockRest.Builder#contentType(String) contentType(String)} - Explicitly set the <c>Content-Type</c> header. |
| </ul> |
| <p> |
| Various other convenience methods for common media types are also provided. |
| </p> |
| <p> |
| The following examples are functionally equivalent for specifying XML serialization: |
| </p> |
| <p class='bpcode w800'> |
| MockRest mr; |
| |
| mr = MockRest.<jsm>build</jsm>(EchoRest.<jk>class</jk>, Xml.<jsf>DEFAULT</jsf>); |
| |
| mr = MockRest.<jsm>build</jsm>(EchoRest.<jk>class</jk>, XmlSerializer.<jsf>DEFAULT</jsf>, XmlParser.<jsf>DEFAULT</jsf>); |
| |
| mr = MockRest.<jsm>create</jsm>(EchoRest.<jk>class</jk>).marshall(Xml.<jsf>DEFAULT</jsf>).build(); |
| |
| mr = MockRest.<jsm>create</jsm>(EchoRest.<jk>class</jk>).serializer(XmlSerializer.<jsf>DEFAULT</jsf>).parser(XmlParser.<jsf>DEFAULT</jsf>).build(); |
| |
| mr = MockRest.<jsm>create</jsm>(EchoRest.<jk>class</jk>).accept(<js>"text/xml"</js>).contentType(<js>"text/xml"</js>).build(); |
| |
| mr = MockRest.<jsm>create</jsm>(EchoRest.<jk>class</jk>).xml().build(); |
| </p> |
| <hr> |
| <p> |
| The {@link oajr.mock2.MockRest} class provides the following methods for creating requests: |
| </p> |
| <ul class='javatree'> |
| <li class='jc'>{@link oajr.mock2.MockRest} |
| <ul> |
| <li class='jm'>{@link oajr.mock2.MockRest#request(String,String) request(String,String)} |
| <li class='jm'>{@link oajr.mock2.MockRest#request(String,String,Object) request(String,String,Object)} |
| <li class='jm'>{@link oajr.mock2.MockRest#get(String) get(String)} |
| <li class='jm'>{@link oajr.mock2.MockRest#put(String,Object) put(String,Object)} |
| <li class='jm'>{@link oajr.mock2.MockRest#post(String,Object) post(String,Object)} |
| <li class='jm'>{@link oajr.mock2.MockRest#delete(String) delete(String)} |
| <li class='jm'>{@link oajr.mock2.MockRest#patch(String,Object) patch(String,Object)} |
| <li class='jm'>{@link oajr.mock2.MockRest#options(String) options(String)} |
| </ul> |
| </ul> |
| <p> |
| For HTTP methods that pass a request body (i.e. <c>PUT</c>,<c>POST</c><c>PATCH</c>), the body object can be any of the following types: |
| </p> |
| <ul> |
| <li><c><jk>byte</jk>[]</c> |
| <li>{@link java.io.Reader} |
| <li>{@link java.io.InputStream} |
| <li>{@link java.lang.CharSequence} |
| </ul> |
| <p> |
| All other body object types are converted to strings using the <c>toString()</c> method. |
| </p> |
| <p> |
| A common tactic is to override a bean's <c>toString()</c> method to return Simple JSON so that |
| instances can be passed to the methods above. |
| </p> |
| <p class='bpcode w800'> |
| <jk>public class</jk> MyBean { |
| |
| ... |
| |
| <ja>@Override</ja> |
| <jk>public</jk> String toString() { |
| SimpleJson.<jsf>DEFAULT</jsf>.toString(<jk>this</jk>); |
| } |
| } |
| </p> |
| <p> |
| 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. |
| </p> |
| <p> |
| The following fluent convenience methods are provided for setting common <c>Accept</c> and <c>Content-Type</c> headers. |
| </p> |
| <ul class='javatree'> |
| <li class='jc'>{@link oajr.mock2.MockServletRequest} |
| <ul> |
| <li class='jm'>{@link oajr.mock2.MockServletRequest#json() json()} |
| <li class='jm'>{@link oajr.mock2.MockServletRequest#xml() xml()} |
| <li class='jm'>{@link oajr.mock2.MockServletRequest#html() html()} |
| <li class='jm'>{@link oajr.mock2.MockServletRequest#plainText() plainText()} |
| <li class='jm'>{@link oajr.mock2.MockServletRequest#msgpack() msgpack()} |
| <li class='jm'>{@link oajr.mock2.MockServletRequest#uon() uon()} |
| <li class='jm'>{@link oajr.mock2.MockServletRequest#urlEnc() urlEnc()} |
| <li class='jm'>{@link oajr.mock2.MockServletRequest#yaml() yaml()} |
| </ul> |
| </ul> |
| <p> |
| The following fluent convenience methods are provided for building up your request. |
| </p> |
| <ul class='javatree'> |
| <li class='jc'>{@link oajr.mock2.MockServletRequest} |
| <ul> |
| <li class='jm'>{@link oajr.mock2.MockServletRequest#header(String,Object) header(String,Object)} |
| <li class='jm'>{@link oajr.mock2.MockServletRequest#query(String,Object) query(String,Object}} |
| <li class='jm'>{@link oajr.mock2.MockServletRequest#formData(String,Object) formData(String,Object)} |
| <li class='jm'>{@link oajr.mock2.MockServletRequest#attribute(String,Object) attribute(String,Object)} |
| <li class='jm'>{@link oajr.mock2.MockServletRequest#body(Object) body(Object)} |
| </ul> |
| </ul> |
| <p> |
| Fluent setters are provided for all common request headers: |
| </p> |
| <ul class='javatree'> |
| <li class='jc'>{@link oajr.mock2.MockServletRequest} |
| <ul> |
| <li class='jm'>{@link oajr.mock2.MockServletRequest#accept(Object) accept(Object)} |
| <li class='jm'>{@link oajr.mock2.MockServletRequest#acceptCharset(Object) acceptCharset(Object)} |
| <li class='jm'>{@link oajr.mock2.MockServletRequest#acceptEncoding(Object) acceptEncoding(Object)} |
| <li class='jm'>{@link oajr.mock2.MockServletRequest#acceptLanguage(Object) acceptLanguage(Object)} |
| <li class='jm'>... |
| </ul> |
| </ul> |
| <p> |
| 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. |
| </p> |
| <ul class='javatree'> |
| <li class='jc'>{@link oajr.mock2.MockServletResponse} |
| <ul> |
| <li class='jm'>{@link oajr.mock2.MockServletResponse#getBody() getBody()} |
| <li class='jm'>{@link oajr.mock2.MockServletResponse#getBodyAsString() getBodyAsString()} |
| <li class='jm'>{@link oajr.mock2.MockServletResponse#assertStatus(int) assertStatus(int)} |
| <li class='jm'>{@link oajr.mock2.MockServletResponse#assertBody(String) assertBody(String)} |
| <li class='jm'>{@link oajr.mock2.MockServletResponse#assertBodyContains(String...) assertBodyContains(String...)} |
| <li class='jm'>{@link oajr.mock2.MockServletResponse#assertBodyMatches(String) assertBodyMatches(String)} |
| <li class='jm'>{@link oajr.mock2.MockServletResponse#assertBodyMatchesRE(String) assertBodyMatchesRE(String)} |
| <li class='jm'>{@link oajr.mock2.MockServletResponse#assertHeader(String,String) assertHeader(String,String)} |
| <li class='jm'>{@link oajr.mock2.MockServletResponse#assertHeaderContains(String,String...) assertHeaderContains(String,String...)} |
| </ul> |
| </ul> |
| <hr> |
| <p> |
| The {@link oajr.mock2.MockRest} class has a debug mode that will cause your HTTP requests and responses to |
| be sent to the console: |
| </p> |
| <p class='bpcode w800'> |
| MockRest mr = MockRest |
| .<jsm>create</jsm>(MyRest.<jk>class</jk>) |
| .debug() |
| .simpleJson() |
| .build(); |
| </p> |
| |