<?xml version="1.0"?>
<!--

    DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.

    Copyright (c) 2012-2014 Oracle and/or its affiliates. All rights reserved.

    The contents of this file are subject to the terms of either the GNU
    General Public License Version 2 only ("GPL") or the Common Development
    and Distribution License("CDDL") (collectively, the "License").  You
    may not use this file except in compliance with the License.  You can
    obtain a copy of the License at
    http://glassfish.java.net/public/CDDL+GPL_1_1.html
    or packager/legal/LICENSE.txt.  See the License for the specific
    language governing permissions and limitations under the License.

    When distributing the software, include this License Header Notice in each
    file and include the License file at packager/legal/LICENSE.txt.

    GPL Classpath Exception:
    Oracle designates this particular file as subject to the "Classpath"
    exception as provided by Oracle in the GPL Version 2 section of the License
    file that accompanied this code.

    Modifications:
    If applicable, add the following below the License Header, with the fields
    enclosed by brackets [] replaced by your own identifying information:
    "Portions Copyright [year] [name of copyright owner]"

    Contributor(s):
    If you wish your version of this file to be governed by only the CDDL or
    only the GPL Version 2, indicate your decision by adding "[Contributor]
    elects to include this software in this distribution under the [CDDL or GPL
    Version 2] license."  If you don't indicate a single choice of license, a
    recipient has the option to distribute your version of this file under
    either the CDDL, the GPL Version 2 or to extend the choice of license to
    its licensees as provided above.  However, if you add GPL Version 2 code
    and therefore, elected the GPL Version 2 license, then the option applies
    only if the new code is made subject to such option by the copyright
    holder.

-->
<!DOCTYPE chapter [<!ENTITY % ents SYSTEM "jersey.ent" > %ents; ]>
<chapter xmlns="http://docbook.org/ns/docbook"
         version="5.0"
         xml:lang="en"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xmlns:xi="http://www.w3.org/2001/XInclude"
         xmlns:xlink="http://www.w3.org/1999/xlink"
         xsi:schemaLocation="http://docbook.org/ns/docbook http://docbook.org/xml/5.0/xsd/docbook.xsd
                             http://www.w3.org/1999/xlink http://www.w3.org/1999/xlink.xsd"
         xml:id="test-framework">

    <title>Jersey Test Framework</title>

    <para>
        Jersey Test Framework originated as an internal tool used for verifying the correct implementation of
        server-side components. Testing RESTful applications became a more pressing issue with "modern" approaches like
        test-driven development and users started to look for a tool that could help with designing and running
        the tests as fast as possible but with many options related to test execution environment.
    </para>

    <para>
        Current implementation of Jersey Test Framework supports the following set of features:

        <itemizedlist>
            <listitem><para>pre-configured client to access deployed application</para></listitem>
            <listitem><para>support for multiple containers - grizzly, in-memory, jdk, simple, jetty</para></listitem>
            <listitem><para>able to run against any external container</para></listitem>
            <listitem><para>automated configurable traffic logging</para></listitem>
        </itemizedlist>

        Jersey Test Framework is primarily based on JUnit but you can run tests using TestNG as well. It works almost out-of-the
        box and it is easy to integrate it within your Maven-based project. While it is usable on all environments where you can
        run JUnit, we support primarily the Maven-based setups.
    </para>

    <section>
        <title>Basics</title>

        <programlisting language="java" linenumbering="numbered">public class SimpleTest extends JerseyTest {

    @Path("hello")
    public static class HelloResource {
        @GET
        public String getHello() {
            return "Hello World!";
        }
    }

    @Override
    protected Application configure() {
        return new ResourceConfig(HelloResource.class);
    }

    @Test
    public void test() {
        final String hello = target("hello").request().get(String.class);
        assertEquals("Hello World!", hello);
    }
}</programlisting>

        <para>
            If you want to develop a test using Jersey Test Framework, you need to subclass &jersey.test.JerseyTest; and
            configure the set of resources and/or providers that will be deployed as part of the test application. This short
            code snippet shows basic resource class <literal>HelloResource</literal> used in tests defined as part of the
            <literal>SimpleTest</literal> class. The overridden <literal>configure</literal> method returns
            a &jersey.server.ResourceConfig; of the test application,that contains only the <literal>HelloResource</literal>
            resource class. &lit.jersey.server.ResourceConfig; is a sub-class of JAX-RS &jaxrs.core.Application;. It is a Jersey
            convenience class for configuring JAX-RS applications. &lit.jersey.server.ResourceConfig; also implements JAX-RS
            &jaxrs.core.Configurable; interface to make the application configuration more flexible.
        </para>
    </section>

    <section>
        <title>Supported Containers</title>

        <para>
            &jersey.test.JerseyTest; supports deploying applications on various containers, all (except the external container
            wrapper) need to have some "glue" code to be supported. Currently Jersey Test Framework provides support for
            Grizzly, In-Memory, JDK (<literal>com.sun.net.httpserver.HttpServer</literal>), Simple HTTP container
            (<literal>org.simpleframework.http</literal>) and Jetty HTTP container (<literal>org.eclipse.jetty</literal>).
        </para>

        <para>
            A test container is selected based on various inputs.
            <link xlink:href="&jersey.javadoc.uri.prefix;/test/JerseyTest.html#getTestContainerFactory()">JerseyTest#getTestContainerFactory()</link>
            is always executed, so if you override it and provide your own version of
            &jersey.test.spi.TestContainerFactory;, nothing else will be considered.
            Setting a system variable
            <link xlink:href="&jersey.javadoc.uri.prefix;/test/TestProperties.html#CONTAINER_FACTORY">TestProperties#CONTAINER_FACTORY</link>
            has similar effect. This way you may defer the decision on which containers you want to run your tests
            from the compile time to the test execution time.
            Default implementation of &lit.jersey.test.spi.TestContainerFactory; looks for container factories on classpath.
            If more than one instance is found and there is a Grizzly test container factory among them, it will be used; if not,
            a warning will be logged and the first found factory will be instantiated.
        </para>

        <para>
            Following is a brief description of all container factories supported in Jersey Test Framework.
            <itemizedlist>
                <listitem>
                    <para>
                        Jersey provides 2 different test container factories based on Grizzly.
                        The <literal>GrizzlyTestContainerFactory</literal> creates a container that can run as a light-weight,
                        plain HTTP container. Almost all Jersey tests are using Grizzly HTTP test container factory.
                        Second factory is <literal>GrizzlyWebTestContainerFactory</literal> that is Servlet-based and supports
                        Servlet deployment context for tested applications. This factory can be useful when testing more complex
                        Servlet-based application deployments.

                        <programlisting language="xml">&lt;dependency&gt;
    &lt;groupId&gt;org.glassfish.jersey.test-framework.providers&lt;/groupId&gt;
    &lt;artifactId&gt;jersey-test-framework-provider-grizzly2&lt;/artifactId&gt;
    &lt;version&gt;&version;&lt;/version&gt;
&lt;/dependency&gt;</programlisting>
                    </para>
                </listitem>

                <listitem>
                    <para>
                        In-Memory container is not a real container. It starts Jersey application and directly calls internal
                        APIs to handle request created by client provided by test framework. There is no network communication
                        involved. This containers does not support servlet and other container dependent features, but it is
                        a perfect choice for simple unit tests.

                        <programlisting language="xml">&lt;dependency&gt;
    &lt;groupId&gt;org.glassfish.jersey.test-framework.providers&lt;/groupId&gt;
    &lt;artifactId&gt;jersey-test-framework-provider-inmemory&lt;/artifactId&gt;
    &lt;version&gt;&version;&lt;/version&gt;
&lt;/dependency&gt;</programlisting>
                    </para>
                </listitem>
                <listitem>
                    <para>
                        <literal>HttpServer</literal> from Oracle JDK is another supported test container.

                        <programlisting language="xml">&lt;dependency&gt;
    &lt;groupId&gt;org.glassfish.jersey.test-framework.providers&lt;/groupId&gt;
    &lt;artifactId&gt;jersey-test-framework-provider-jdk-http&lt;/artifactId&gt;
    &lt;version&gt;&version;&lt;/version&gt;
&lt;/dependency&gt;</programlisting>
                    </para>
                </listitem>
                <listitem>
                    <para>
                        Simple container (<literal>org.simpleframework.http</literal>) is another light-weight HTTP container
                        that integrates with Jersey and is supported by Jersey Test Framework.

                        <programlisting language="xml">&lt;dependency&gt;
    &lt;groupId&gt;org.glassfish.jersey.test-framework.providers&lt;/groupId&gt;
    &lt;artifactId&gt;jersey-test-framework-provider-simple&lt;/artifactId&gt;
    &lt;version&gt;&version;&lt;/version&gt;
&lt;/dependency&gt;</programlisting>
                    </para>
                </listitem>
                <listitem>
                    <para>
                        Jetty container (<literal>org.eclipse.jetty</literal>) is another high-performance, light-weight HTTP server
                        that integrates with Jersey and is supported by Jersey Test Framework.

                        <programlisting language="xml">&lt;dependency&gt;
    &lt;groupId&gt;org.glassfish.jersey.test-framework.providers&lt;/groupId&gt;
    &lt;artifactId&gt;jersey-test-framework-provider-jetty&lt;/artifactId&gt;
    &lt;version&gt;&version;&lt;/version&gt;
&lt;/dependency&gt;</programlisting>
                    </para>
                </listitem>
            </itemizedlist>
        </para>
    </section>

    <section xml:id="testng">
        <title>Running TestNG Tests</title>

        <para>
            It is possible to run not only JUnit tests but also tests based on TestNG. In order to do this you need to make sure
            the following 2 steps are fulfilled:

            <itemizedlist>
                <listitem>
                    <para>
                        Extend &jersey.test.JerseyTestNg;, or one of it's inner classes &jersey.test.JerseyTestNg.ContainerPerClassTest;
                        / &jersey.test.JerseyTestNg.ContainerPerMethodTest;, instead of &jersey.test.JerseyTest;.
                    </para>
                </listitem>
                <listitem>
                    <para>
                        Add TestNG to your class-patch, i.e.:

                        <programlisting language="xml">&lt;dependency&gt;
    &lt;groupId&gt;org.glassfish.jersey.test-framework&lt;/groupId&gt;
    &lt;artifactId&gt;jersey-test-framework-core&lt;/artifactId&gt;
    &lt;version&gt;&version;&lt;/version&gt;
&lt;/dependency&gt;
&lt;dependency&gt;
    &lt;groupId&gt;org.testng&lt;/groupId&gt;
    &lt;artifactId&gt;testng&lt;/artifactId&gt;
    &lt;version&gt;...&lt;/version&gt;
&lt;/dependency&gt;</programlisting>
                    </para>
                </listitem>
            </itemizedlist>
        </para>
        <para>
            To discuss the former requirement in more depth we need to take a look at the differences between JUnit and TestNG.
            JUnit creates a new instance of a test class for every test present in that class which, from the point of view of
            Jersey Test Framework, means that new test container and client is created for each test of a test class. However,
            TestNG creates only one instance of a test class and the initialization of the test container depends more on
            setup/teardown methods (driven by <literal>@BeforeXXX</literal> and <literal>@AfterXXX</literal> annotations) than in
            JUnit. This means that, basically, you can start one instance of test container for all tests present in a test class
            or separate test container for each and every test. For this reason a separate subclasses of &jersey.test.JerseyTestNg;
            have been created:

            <itemizedlist>
                <listitem>
                    <para>
                        &jersey.test.JerseyTestNg.ContainerPerClassTest; creates one container to run all the tests in. Setup method
                        is annotated with <literal>@BeforeClass</literal>, teardown method with <literal>@AfterClass</literal>.
                    </para>
                    <para>
                        For example take a look at <literal>ContainerPerClassTest</literal> test. It contains two test
                        methods (<literal>first</literal> and <literal>second</literal>), one singleton resource that returns an
                        increasing sequence of number. Since we spawn only one instance of a test container for the whole class the
                        value expected in the first test is <literal>1</literal> and in the second it's <literal>2</literal>.

                        <programlisting language="java" linenumbering="numbered">public class ContainerPerClassTest extends JerseyTestNg.ContainerPerClassTest {

    @Path("/")
    @Singleton
    @Produces("text/plain")
    public static class Resource {

        private int i = 1;

        @GET
        public int get() {
            return i++;
        }
    }

    @Override
    protected Application configure() {
        return new ResourceConfig(Resource.class);
    }

    @Test(priority = 1)
    public void first() throws Exception {
        test(1);
    }

    @Test(priority = 2)
    public void second() throws Exception {
        test(2);
    }

    private void test(final Integer expected) {
        final Response response = target().request().get();

        assertEquals(response.getStatus(), 200);
        assertEquals(response.readEntity(Integer.class), expected);
    }
}</programlisting>
                    </para>
                </listitem>
                <listitem>
                    <para>
                        &jersey.test.JerseyTestNg.ContainerPerMethodTest; creates separate container for each test. Setup method
                        is annotated with <literal>@BeforeMethod</literal>, teardown method with <literal>@AfterMethod</literal>.
                    </para>
                    <para>
                        We can create a similar test to the previous one. Take a look at <literal>ContainerPerMethodTest</literal>
                        test. It looks the same except the expected values and extending class: it contains two test
                        methods (<literal>first</literal> and <literal>second</literal>), one singleton resource that returns an
                        increasing sequence of number. In this case we create a separate test container for each test so
                        value expected in the first test is <literal>1</literal> and in the second it's also <literal>1</literal>.

                        <programlisting language="java" linenumbering="numbered">public class ContainerPerMethodTest extends JerseyTestNg.ContainerPerMethodTest {

    @Path("/")
    @Singleton
    @Produces("text/plain")
    public static class Resource {

        private int i = 1;

        @GET
        public int get() {
            return i++;
        }
    }

    @Override
    protected Application configure() {
        return new ResourceConfig(Resource.class);
    }

    @Test
    public void first() throws Exception {
        test(1);
    }

    @Test
    public void second() throws Exception {
        test(1);
    }

    private void test(final Integer expected) {
        final Response response = target().request().get();

        assertEquals(response.getStatus(), 200);
        assertEquals(response.readEntity(Integer.class), expected);
    }
}</programlisting>
                    </para>
                </listitem>
            </itemizedlist>
        </para>

        <para>
            If you need more complex setup of your test you can achieve this by directly extending the &jersey.test.JerseyTestNg;
            class create setup/teardown methods suited to your needs and provide a strategy for storing and handling a test
            container / client instance (see <literal>JerseyTestNg.configureStrategy(TestNgStrategy)</literal> method).
        </para>
    </section>

    <section>
        <title>Advanced features</title>

        <section>
            <title>&lit.jersey.test.JerseyTest; Features</title>

            <para>&lit.jersey.test.JerseyTest; provide
                <link xlink:href="&jersey.javadoc.uri.prefix;/test/JerseyTest.html#enable(java.lang.String)">enable(...)</link>,
                <link xlink:href="&jersey.javadoc.uri.prefix;/test/JerseyTest.html#forceEnable(java.lang.String)">forceEnable(...)</link>
                and <link xlink:href="&jersey.javadoc.uri.prefix;/test/JerseyTest.html#disable(java.lang.String)">disable(...)</link>
                methods, that give you control over configuring values of the properties defined and described in the
                &lit.jersey.test.TestProperties; class. A typical code that overrides the default property values is listed
                below:

                <programlisting language="java" linenumbering="numbered">public class SimpleTest extends JerseyTest {
    // ...

    @Override
    protected Application configure() {
        enable(TestProperties.LOG_TRAFFIC);
        enable(TestProperties.DUMP_ENTITY);

        // ...

    }
}</programlisting>

                The code in the example above enables test traffic logging (inbound and outbound headers) as well as
                dumping the HTTP message entity as part of the traffic logging.
            </para>
        </section>


        <section>
            <title>External container</title>

            <para>
                Complicated test scenarios may require fully started containers with complex setup configuration, that is not
                easily doable with current Jersey container support. To address these use cases, Jersey Test Framework providers
                general fallback mechanism - an External Test Container Factory. Support of this external container "wrapper" is
                provided as the following module:

                <programlisting language="xml">&lt;dependency&gt;
    &lt;groupId&gt;org.glassfish.jersey.test-framework.providers&lt;/groupId&gt;
    &lt;artifactId&gt;jersey-test-framework-provider-external&lt;/artifactId&gt;
    &lt;version&gt;&version;&lt;/version&gt;
&lt;/dependency&gt;</programlisting>

                As indicated, the "container" exposed by this module is just a wrapper or stub, that redirects all request to
                a configured host and port. Writing tests for this container is same as for any other but you have to provide
                the information about host and port during the test execution:

                <screen>mvn test -Djersey.test.host=myhost.org -Djersey.config.test.container.port=8080</screen>
            </para>
        </section>

        <section>
            <title>Test Client configuration</title>

            <para>
                Tests might require some advanced client configuration. This is possible by overriding
                <link xlink:href="&jersey.javadoc.uri.prefix;/test/JerseyTest.html#configureClient(org.glassfish.jersey.client.ClientConfig)">configureClient(ClientConfig clientConfig)</link>
                method. Typical use case for this is registering more providers, such as &jaxrs.ext.MessageBodyReader;s or
                &jaxrs.ext.MessageBodyWriter;s, or enabling additional features.
            </para>
        </section>

        <section>
            <title>Accessing the logged test records programmatically</title>

            <para>
                Sometimes you might need to check a logged message as part of your test assertions. For this purpose Jersey Test
                Framework provides convenient access to the logged records via
                <link xlink:href="&jersey.javadoc.uri.prefix;/test/JerseyTest.html#getLastLoggedRecord()">JerseyTest#getLastLoggedRecord()</link>
                and
                <link xlink:href="&jersey.javadoc.uri.prefix;/test/JerseyTest.html#getLoggedRecords()">JerseyTest#getLoggedRecords()</link>
                methods. Note that this feature is not enabled by default, see
                <link xlink:href="&jersey.javadoc.uri.prefix;/test/TestProperties.html#RECORD_LOG_LEVEL">TestProperties#RECORD_LOG_LEVEL</link>
                for more information.
            </para>
        </section>
    </section>

    <section xml:id="parallel">
        <title>Parallel Testing with Jersey Test Framework</title>

        <para>
            For a purpose of running multiple test containers in parallel you need to set the
            <link xlink:href='&jersey.javadoc.uri.prefix;/test/TestProperties.CONTAINER_PORT.html'>TestProperties.CONTAINER_PORT</link>
            to <literal>0</literal> value. This will tell Jersey Test Framework (and the underlying test container) to use the
            first available port.
        </para>

        <para>
            You can set the value as a system property (via command line option) or directly in the test (to not affect ports of
            other tests):

            <programlisting language="java" linenumbering="numbered">@Override
    protected Application configure() {
        // Find first available port.
        forceSet(TestProperties.CONTAINER_PORT, "0");

        return new ResourceConfig(Resource.class);
    }</programlisting>
        </para>

        <para>
            The easiest way to setup your JUnit or TestNG tests to run in parallel is to configure Maven Surefire plugin. You can
            do this via configuration options <literal>parallel</literal> and <literal>threadCount</literal>, i.e.:

                            <programlisting language="xml">...
&lt;configuration&gt;
    &lt;parallel&gt;methods&lt;/parallel&gt;
    &lt;threadCount&gt;5&lt;/threadCount&gt;
    ...
&lt;/configuration&gt;
...</programlisting>

            For more information about this topic consult the following Maven Surefire articles:

            <itemizedlist>
                <listitem>
                    <para><link xlink:href="http://maven.apache.org/surefire/maven-surefire-plugin/examples/fork-options-and-parallel-execution.html">Fork Options and Parallel Test Execution</link></para>
                </listitem>
                <listitem>
                    <para><link xlink:href="http://maven.apache.org/surefire/maven-surefire-plugin/examples/testng.html#Running_tests_in_parallel">Using TestNG - Running tests in parallel</link></para>
                </listitem>
                <listitem>
                    <para><link xlink:href="http://maven.apache.org/surefire/maven-surefire-plugin/examples/junit.html#Running_tests_in_parallel">Using JUnit - Running tests in parallel</link></para>
                </listitem>
            </itemizedlist>
        </para>
    </section>
</chapter>
