|  | <?xml version="1.0"?> | 
|  | <!-- | 
|  |  | 
|  | Copyright (c) 2012, 2021 Oracle and/or its affiliates. All rights reserved. | 
|  |  | 
|  | This program and the accompanying materials are made available under the | 
|  | terms of the Eclipse Public License v. 2.0, which is available at | 
|  | http://www.eclipse.org/legal/epl-2.0. | 
|  |  | 
|  | This Source Code may also be made available under the following Secondary | 
|  | Licenses when the conditions for such availability set forth in the | 
|  | Eclipse Public License v. 2.0 are satisfied: GNU General Public License, | 
|  | version 2 with the GNU Classpath Exception, which is available at | 
|  | https://www.gnu.org/software/classpath/license.html. | 
|  |  | 
|  | SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0 | 
|  |  | 
|  | --> | 
|  |  | 
|  | <!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>) | 
|  | - since Jersey 3.x HTTP Jetty container requires JDK 11+. | 
|  | </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"><dependency> | 
|  | <groupId>org.glassfish.jersey.test-framework.providers</groupId> | 
|  | <artifactId>jersey-test-framework-provider-grizzly2</artifactId> | 
|  | <version>&version;</version> | 
|  | </dependency></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"><dependency> | 
|  | <groupId>org.glassfish.jersey.test-framework.providers</groupId> | 
|  | <artifactId>jersey-test-framework-provider-inmemory</artifactId> | 
|  | <version>&version;</version> | 
|  | </dependency></programlisting> | 
|  | </para> | 
|  | </listitem> | 
|  | <listitem> | 
|  | <para> | 
|  | <literal>HttpServer</literal> from JDK is another supported test container. | 
|  |  | 
|  | <programlisting language="xml"><dependency> | 
|  | <groupId>org.glassfish.jersey.test-framework.providers</groupId> | 
|  | <artifactId>jersey-test-framework-provider-jdk-http</artifactId> | 
|  | <version>&version;</version> | 
|  | </dependency></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"><dependency> | 
|  | <groupId>org.glassfish.jersey.test-framework.providers</groupId> | 
|  | <artifactId>jersey-test-framework-provider-simple</artifactId> | 
|  | <version>&version;</version> | 
|  | </dependency></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. Shall be used along with JDK 11+. | 
|  |  | 
|  | <programlisting language="xml"><dependency> | 
|  | <groupId>org.glassfish.jersey.test-framework.providers</groupId> | 
|  | <artifactId>jersey-test-framework-provider-jetty</artifactId> | 
|  | <version>&version;</version> | 
|  | </dependency></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 its 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"><dependency> | 
|  | <groupId>org.glassfish.jersey.test-framework</groupId> | 
|  | <artifactId>jersey-test-framework-core</artifactId> | 
|  | <version>&version;</version> | 
|  | </dependency> | 
|  | <dependency> | 
|  | <groupId>org.testng</groupId> | 
|  | <artifactId>testng</artifactId> | 
|  | <version>...</version> | 
|  | </dependency></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"><dependency> | 
|  | <groupId>org.glassfish.jersey.test-framework.providers</groupId> | 
|  | <artifactId>jersey-test-framework-provider-external</artifactId> | 
|  | <version>&version;</version> | 
|  | </dependency></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 similar to 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">... | 
|  | <configuration> | 
|  | <parallel>methods</parallel> | 
|  | <threadCount>5</threadCount> | 
|  | ... | 
|  | </configuration> | 
|  | ...</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> |