1  Introduction

ObMimic from OpenBrace Limited is a library of fully-configurable concrete implementations of all of the Servlet API’s interfaces and abstract classes, for use as “test doubles” in “out-of-container” testing of servlets, filters, listeners and any other code that uses Servlet API classes. We call these implementations of the Servlet API classes “mimics”, as they accurately mimic the behaviour of normal servlet-container implementations of the corresponding Servlet API classes.

With ObMimic, you can use normal Java code (for example, within normal JUnit or TestNG test cases) to create instances of HttpServletRequest, HttpServletResponse, ServletContext, HttpSession, and other Servlet API interfaces and classes for use in your tests, and can configure and inspect these instances as necessary — without any need to deploy your code into a servlet container or use complex “in-container” testing tools, and without any networking overheads.

2  Prerequisites

Prerequisites for using ObMimic are:

  • A JDK or JRE for Java SE 5 or higher (with Java SE 8 recommended, and with support for Java SE 5 likely to be dropped once Java SE 9 is released).
  • A Servlet API or Java EE API library that is suitable for use at run-time. That is, a “servlet.jar”, “servlet-api.jar”, “javax.servlet.jar”, “javax.servlet-api.jar”, “javaee.jar” or other such library that provides the Servlet API and is not one of the Java EE API jars that are deliberately restricted to compile-time use only (such as the “javaee-api-7.0.jar” and “javaee-web-api-7.0.jar” archives from the java.net website and elsewhere). For this release of ObMimic, this must be for version 2.4, 2.5, 3.0 or 3.1 of the Servlet API (with Servlet 3.1 recommended).
  • If you are using Java SE 5 and are obtaining the Servlet API from a library other than a full Java EE library for Java EE 5 or higher then an additional “Common Annotations” library will also be needed to provide the javax.annotation package.

For more precise details of these requirements, and where to obtain the necessary libraries if you do not already have them, refer to the System Requirements section of ObMimic’s Read Me document.

Note that:

  • Whilst ObMimic itself is compatible with Java SE 5 onwards, other libraries that you are using may impose higher requirements (for example, if you are using a Servlet 3.1 or Java EE 7 API library this will itself require the use of Java SE 7 or higher).
  • Any code that you intend testing with ObMimic will itself already require a Servlet API library, so any project using ObMimic will probably already have a Java EE or Servlet API library (although if you are currently using a library for a Servlet API version prior to 2.4 you will need to use a suitable Servlet 2.4, 2.5, 3.0 or 3.1 library instead; and if you are using a Java EE API jar that is deliberately restricted to compile-time only use then you will need to use a different Servlet API library for your test runs).
  • In general, ObMimic requires a Servlet API library for the highest version of the Servlet API that you wish to simulate, and will throw an “ApiElementAbsentException” if an attempt is made to invoke a Servlet API method that does not exist in the Servlet API library being used. (However, as there are only minimal differences between Servlet 2.4 and Servlet 2.5, ObMimic accommodates the differences between these two particular versions and can simulate Servlet 2.5 even when using a Servlet 2.4 library).
  • Subject to the above restriction, ObMimic handles each Servlet API call as appropriate for whichever version of the API it is configured to simulate (with Servlet 2.5 as the default), regardless of which version of the Servlet API is actually present on the classpath .

3  Installation

The recommended steps for installing ObMimic are:

  • Unzip the ObMimic-1.2.001.zip archive into the location where you wish to install ObMimic. This will result in an “ObMimic-1.2.001” directory at that location, with contents as described in ObMimic’s Read Me document.
  • Create an OBMIMIC_HOME environment variable set to the path of the ObMimic installation’s root directory (that is, its “ObMimic-1.2.001” directory). This is used as the default mechanism by which ObMimic determines the location of its configuration and licence files. You may also find this useful when specifying your own paths to ObMimic’s libraries and Javadoc.
  • If you have a “Professional” or “Enterprise” licence for ObMimic, place the licence file into the ObMimic installation’s /licence subdirectory.

Although the use of an OBMIMIC_HOME environment variable and placing any licence files into the /licence subdirectory are recommended, neither are strictly necessary if you are using ObMimic’s “Community” edition with no licence file and its built-in default values for all configuration settings, nor if you are explicitly specifying the location of licence and configuration files by some other means. For further details and alternatives, refer to the “How To” guides How to enable “Professional” and “Enterprise” edition features and How to set an ObMimic configuration property.

You may also wish at this point to review or modify the ObMimic configuration settings in the installation’s /config/config.properties file. This file includes comments explaining each of the relevant properties (but note that many of these properties only accept non-default values if you have a valid “Professional” or “Enterprise” licence).

4  Adding ObMimic To Your Projects

Once ObMimic has been installed, you can use ObMimic in your tests by adding its /lib/obmimic.jar to their classpath (for projects using Maven™, see the accompanying “How To” guide How to add ObMimic to a Maven-based project). ObMimic’s “mimic” classes and other public classes will then be available for use within your code.

You should also ensure that you have convenient access to the ObMimic Javadoc located at /docs/api within the ObMimic installation. For example, you should configure any IDE you are using so that it uses this Javadoc for all of the packages provided by the “obmimic.jar” archive (that is, all com.openbrace.* packages). Alternatively you may wish to create a desktop shortcut to the Javadoc’s index.html page.

More generally, the use of a modern Java IDE that supports “code completion” and integrated display of Javadoc is strongly recommended, as this provides the easiest way to find your way around the relevant ObMimic classes and Javadoc whilst working on your code.

You may also find it useful to ensure that you have convenient access to:

  • ObMimic’s “Overview of MimicState Classes” document at docs/pages/MimicStateSummary.html within the ObMimic installation. This summarizes the contents of each of ObMimic’s “MimicState” classes, so as to help you find your way around the internal state of each mimic class when configuring and inspecting mimic instances.
  • ObMimic’s “How To” guide at docs/pages/howto/index.html within the ObMimic installation. This provides guidance on how to use ObMimic for a variety of specific commonly-encountered tasks, and includes code examples showing the use of various ObMimic features and facilities.

Depending on how classpaths are defined for your normal code and for your tests, you may also need to add further libraries to the classpath used by your tests:

  • If it is not already present you will need to add a suitable Servlet API 2.4, 2.5, 3.0 or 3.1 library to the classpath used for compiling and running your tests, as explained in Prerequisites above.
  • If running on Java SE 5 and not obtaining the Servlet API from a full Java EE library for Java EE 5 or higher you will also need a suitable “Common Annotations” library, as explained in Prerequisites above.
  • The classpath for running the tests will also need to include any other libraries that are needed by the code being tested. In particular, your tests may now be testing code that they were not previously executing, and so may for the first time require whatever other libraries are needed by the code you are testing.

Note that most or all of these libraries are likely to already be needed to compile the code that you are using ObMimic to test, but this may be the first time that they have been needed when compiling and running your tests (and in some cases ObMimic may require a higher version of the relevant Servlet API library than you were previously using).

5  Overview of ObMimic

ObMimic provides a set of “mimic” classes for all of the Servlet API’s interfaces and abstract classes. These are “plain Java” concrete implementations of the relevant Servlet API interfaces and abstract classes, and are based on the Servlet API Javadoc (interpreted as completely and as strictly as possible). Each mimic instance has a mimicState property through which all relevant details of its logical internal state can be configured and examined as necessary.

These mimic classes can thus be used in JUnit tests, TestNG tests, or other such “plain Java” tests as fully-configurable and fully-examinable “test doubles” for Servlet API objects. They can be used for out-of-container testing of servlets, filters, listeners and any other code that depends on the Servlet API — including code that uses frameworks or libraries that depend on the Servlet API. For example, you can use ObMimic for out-of-container testing of JSF pages, as described in the “How To” guide How to test JSF pages.

The mimic classes provided by ObMimic are as follows:

  • The mimic classes for the interfaces and classes of the Servlet API’s javax.servlet package can be found in ObMimic’s com.openbrace.obmimic.mimic.servlet package.
  • The mimic classes for the interfaces and classes of the Servlet API’s javax.servlet.http package can be found in ObMimic’s com.openbrace.obmimic.mimic.servlet.http package.
  • The class name of each mimic class consists of the relevant Servlet API interface or class name suffixed with “Mimic” (for example, HttpServletRequestMimic).

Each such “mimic” class includes:

  • A simple no-argument constructor that constructs a ready-to-use instance with suitable default values for all of its properties and content. (Various other mechanisms for creating instances of mimic classes are also provided — for details, refer to the “How To” guide How to create a mimic instance of a Servlet API interface or abstract class).
  • A mimicState property, accessible via each instance’s getMimicState method, through which all aspects of the mimic’s logical internal state can be configured and examined. This includes the ability to configure details that are “read only” in the relevant Servlet API interface or class, and to examine details that are “write only” in the relevant Servlet API interface or class, and to configure any behaviour that may vary between different servlet containers or underlying platforms. It also includes the ability to force Servlet API methods that can potentially throw various checked exceptions to do so (so that code that handles such exceptions can be tested).
  • A concrete implementation of each of the relevant Servlet API methods. These are based on a strict interpretation of each method’s Servlet API Javadoc, and are implemented by appropriate interaction with the instance’s mimicState. The mimic’s Javadoc for each such Servlet API method implementation includes complete and precise details of exactly how it interacts with the mimicState, and also explains any relevant assumptions or interpretation of the Servlet API Javadoc that affect the implementation.

Use of ObMimic within a test typically consists of creating the necessary mimic instances, configuring their mimicStates as required for that particular test, passing the mimic instances to the code that is being tested, and then inspecting their mimicStates as necessary to check the results of the test.

For example:

  • Wherever you need an HttpServletRequest, you can create an HttpServletRequestMimic instance and use its getMimicState method to retrieve an HttpServletRequestState instance through which you can configure the request’s content and properties as desired. For example, you can use its headers sub-component to configure the request with any HTTP headers you want it to have.
  • Similarly, wherever you need an HttpServletResponse you can create and use an HttpServletResponseMimic. After carrying out the desired test(s), you can use its getMimicState method to retrieve an HttpServletResponseState through which you can examine the response’s content and properties in order to check what effect the test(s) have had on the response. For example, you can use its getBodyContentAsByteArray() method or getBodyContentAsString() method to retrieve the body content that has been written into the response.
  • Similarly, you can use ObMimic to construct, configure and examine ServletContexts, HttpSessions, and any other Servlet API objects that you require.

To a large extent the use of ObMimic thus hinges on finding your way around each mimic instance’s mimicState and its subcomponents, and determining how to use their properties and methods to configure each mimic as necessary for your tests and to check the results of your tests. To help with this:

  • An Overview of MimicState classes document is provided which summarizes the contents of each mimicState’s class (with links to the corresponding Javadoc).
  • A set of How To guides are provided to give guidance on how to use ObMimic for specific commonly-encountered tasks (with example code where appropriate).
  • Extensive Javadoc is provided for each of the various mimicState classes and their subcomponent classes, and for how each mimic class’s Servlet API method implementations interact with its mimicState.

ObMimic also includes the following additional facilities:

  • Professional and Enterprise Editions only: ObMimic can be configured to simulate different versions of the Servlet API (either in general or programmatically within individual tests), in addition to its default behaviour of simulating version 2.5 of the Servlet API. For details, refer to the “How To” guide How to configure the Servlet API version to be simulated.
  • Professional and Enterprise Editions only: In addition to its mimicState, each mimic instance also has a mimicHistory property that can be used to record details of the sequence of Servlet API method calls made to the instance and the results of each such call, and to subsequently examine these details. This recording of calls can be turned “on” and “off” on individual mimic instances whenever required. For details, refer to the “How To” guide How to examine a history of the Servlet API calls made to a Mimic.
  • Professional and Enterprise Editions only: Similarly, and as an alternative and supplement to the mimicHistory facilities, each mimic instance also has a mimicListeners property into which you can install any number of MethodInvocationListener and MethodExitListener instances. These are then notified of the details and results of each Servlet API method call as and when each call occurs. These listeners can not only examine the details of the method call and its results, but can also be used to modify the argument values passed to the method and the results returned to the caller (for example, if you ever need different behaviour from a Servlet API method than that provided by ObMimic). For details, refer to the “How To” guide How to intercept, examine and modify the Servlet API calls to a Mimic.
  • ObMimic includes a variety of additional classes that you can use to explicitly manage the “lifecycle” of a mimic instance where this is relevant to the behaviour of the corresponding Servlet API object but is not directly controllable through its Servlet API methods (for example, for “initializing” and “destroying” a ServletContext, including appropriate invocations of any relevant listeners). Each such class is defined in the “com.openbrace.obmimic.lifecycle.servlet” or “com.openbrace.obmimic.lifecycle.servlet.http” package as appropriate, and has a name consisting of the mimic’s class name suffixed with “Manager” (for example, ServletContextMimicManager). Refer to each such class’s Javadoc for full details.
  • For application code that uses JNDI look-ups, ObMimic includes a basic in-memory JNDI simulation that can be used to make appropriate objects available at the required JNDI “java:” URIs. For details, refer to the “How To” guide How to cater for JNDI look-ups and the Javadoc for ObMimic’s com.openbrace.obmimic.jndi package.
  • ObMimic contains a variety of other classes and helper methods that it uses internally (both to aid in the implementation of Servlet API functionality such as request dispatching and session handling, and for more general use), and you may find some of these facilities of use in your own code. For details, refer to the ObMimic Javadoc.

For more extensive details on various aspects of ObMimic, please refer to ObMimic’s How To guides and to the ObMimic Javadoc.

6  Additional ObMimic Notes

6.1 Mimic and MimicState Classes

Each mimic class implements the com.openbrace.obmimic.core.Mimic interface and has a corresponding class that is used for each instance’s mimicState property and which implements the com.openbrace.obmimic.core.MimicState interface. These MimicState classes represents ObMimic’s logical model of the internal state of the various Servlet API interface and abstract classes. They are each designed to support all of the relevant Servlet API methods, including correct handling of Servlet API methods that return related values or otherwise need to be consistent with each other), whilst being fully configurable and fully examinable. In many cases the MimicState classes contain subcomponents that are themselves MimicState classes.

Each mimic instance uses a single instance of the relevant MimicState class throughout its lifetime, with this being constructed when the mimic instance is constructed, and with each MimicState instance being initialized on construction with reasonable default values for all of its properties. This ensures that newly-constructed mimics and MimicState instances are immediately fully valid and ready for use, and you need only configure those properties for which you require specific non-default values.

Each MimicState class also includes:

  • A clear method that resets the instance back to its initial/default contents.
  • A copyFrom method that populates the instance’s contents by copying them from another instance of the same class.
  • An equals implementation that compares the instance’s contents with those of another such instance (in a manner consistent with its copyFrom method, such that copyFrom always results in the relevant instances being equal to each other).

In particular, these mechanisms allow you to copy and compare the internal state of mimic instances. For example, you can construct and configure a mimic for use in a test, create a instance of the relevant MimicState class and copy the contents of the mimic’s mimicState into it, and then modify this mimicState as necessary to reflect the expected effects of the test. After running the test you can then compare the mimic’s updated mimicState against this “expected result” MimicState using their normal equals method (thus checking that the expected changes have occurred but the mimic’s content is otherwise unchanged).

Each MimicState class’s Javadoc gives full details of its properties and methods, including the default values for all of its properties, full details of each method’s argument validation and interpretation, and the precise behaviour of its copyFrom and equals implementations. In addition, a summary of the properties, methods and subcomponents of each mimicState class is given in the accompanying Overview of MimicState Classes document.

Note that the use of a separate mimicState property for each mimic class’s “internal state” ensures that the facilities for configuring and inspecting the mimic’s internal state are cleanly separated from its normal Servlet API methods.

6.2 Servlet Contexts

Many MimicState classes include a servletContext property that references the javax.servlet.ServletContext with which the mimic instance is associated (representing the web-application and servlet context within which it is being used).

To simplify the use of ObMimic, all such properties have an initial/default value that references a single default ServletContextMimic. Thus if you take no other action, all of the mimic instances that you create will be configured to share this single default ServletContextMimic instance as their servletContext property. This default ServletContextMimic can also be accessed directly by means of the static getDefaultServletContext method of class com.openbrace.obmimic.mimic.servlet.ServletContextMimicFactory.

You do, of course, remain free to explicitly construct other ServletContextMimic instances, and to configure individual mimics to use specific instances as their servletContexts.

Note also that the ServletContextMimic’s mimicState represents all of the relevant servlet-context and web-application details, and includes:

  • A webAppConfig subcomponent that represents the values specified by the web-application’s deployment descriptor. For details, refer to the “How To” guide How to simulate a web-application’s deployment-descriptor settings.
  • A webAppResources subcomponent that represents the web-application’s “resources” (essentially, the files within the web-application). For details, refer to the “How To” guide How to simulate a web-application’s static resources..
  • A container subcomponent that represents all relevant details of the servlet container and underlying environment in which the web-application is notionally being used. For details, refer to the relevant ObMimic Javadoc. Note that each ServletContextState has its own independent container instance.

Also note that:

  • The com.openbrace.obmimic.support.DispatchingUtilities class provides a static dispatch method that can be used to carry out a “REQUEST”-type dispatch of any given request and response to the appropriate filters and target servlet or static resource for any given context-relative path within a given ServletContextMimic based on its configuration (including automatic construction and initialization of the relevant filters and servlets where necessary).
  • Similarly, the com.openbrace.obmimic.mimic.servlet.FilterChainMimicFactory class includes static methods that can be used for constructing appropriate FilterChainMimic instances for processing a request and response for a given servlet name or context-relative path and a given “dispatcher type” (request, forward, include or error) within a given ServletContextMimic based on its configuration (including automatic construction and initialization of the relevant filters and servlets where necessary).
  • For further details regarding request dispatching, refer to the “How To” guide How to handle request dispatching.

6.3 API Ambiguities

The Servlet API Javadoc appears to be somewhat ambiguous or incomplete for many situations. For example, there any many cases where it does not specify whether a given argument value should be considered valid or invalid, or how it should be handled if considered invalid.

ObMimic treats any Servlet API call for which the Servlet API Javadoc is considered ambiguous or incomplete as an “API Ambiguity”. These are documented in the relevant mimic class’s Javadoc, which defines the situations in which the various different API ambiguities occur, and uses a custom Javadoc tag to formally classify and identify each such API ambiguity within each Servlet API method implementation.

For the “Community” edition of ObMimic, all such API ambiguities can only be handled by throwing an unchecked com.openbrace.obmimic.ambiguity.ApiAmbiguityException to indicate that the code issuing the call depends on Servlet API behaviour that is not explicitly specified by the Servlet API Javadoc. This ensures that you can detect any such calls in your code. Any calls that are free of such API ambiguities should be safe for use on any servlet container, with reliable behaviour and results regardless of the container’s individual implementation of the Servlet API method.

For the “Professional” and “Enterprise” versions of ObMimic, you can optionally configure other options for how ObMimic handles each API ambiguity (for example, to ignore the call entirely, or to throw a specified type of exception, or to process the call based on some reasonable assumption of the expected behaviour). The mimic’s Javadoc spells out the options that are supported for each API ambiguity and the behaviour that results from each option, as well as giving the details necessary to precisely identify that particular API ambiguity when configuring the ambiguity handling.

The actual configuration of API ambiguity handling can be done via ObMimic’s /config/config.properties file (or any alternative file that you are using in its place), or via Java system properties, or programmatically within your tests as necessary. The API ambiguity handling can be configured for either individual, specific ambiguities or more broadly for various sets of ambiguities (for example, all API ambiguities of a particular type, or all API ambiguities of a particular type within a particular Servlet API interface etc).

For details, refer to the “How To” guide How to configure handling of “API ambiguities”.

6.4 Frameworks and “Coarse-Grained” Tests

ObMimic is not a servlet container, and implements the various Servlet API interfaces and classes based on their Javadoc rather than implementing the Servlet specification as a whole. However, its implementation of the Servlet API interface and classes is intended to be sufficiently complete and accurate that anything that can run on top of a Servlet API implementation should be able to run on top of suitably-configured mimics (subject, of course, to any other dependencies the code may have).

For example, ObMimic’s ServletContextMimic provides full support for the retrieval and use of RequestDispatcher instances, including appropriate handling of servlet and filter mappings, wrapping/adjustment of requests and responses during “forward”s and “includes”, processing of static resources etc.

ObMimic can thus be used for a variety of “integration” or “coarse grained” tests across multiple components, and for tests that involve the use of web-application frameworks and libraries, as well as for detailed “unit testing” of individual classes or components in isolation.

As an example, it is possible to use ObMimic for out-of-container testing of complete JSF pages, as described in the “How To” guide How to test JSF pages.

6.5 Detailed Tests

Because mimic instances can be programmatically configured and there is no servlet container involved, it is possible to repeat tests with different values of deployment-descriptor settings or container-specific details that would normally be difficult to vary when executing code within a real servlet container.

For example, this makes it possible to test the use of different values for a servlet filter’s “init parameters”, or to run tests for different values of “server info” strings, or to test code that uses Servlet API methods that individual servlet containers can choose to either allow or prohibit. Similarly, mimic instances can be explicitly configured to make relevant Servlet API methods throw checked exceptions, which can be difficult to arrange when running within a real servlet container. For example, this makes it possible to test code that handles unexpected IOExceptions from a Servlet API call.

ObMimic can thus be used for more detailed testing than is usually feasible with any “in-container” approach.

7  Example Code

7.1 Constructing Mimic Instances

At its simplest, if you merely require an instance of some Servlet API interface or abstract class and are not concerned with its precise content (or if ObMimic’s default values are acceptable), you can simply use the relevant mimic class’s no-argument constructor to obtain a suitable instance.

For example, you can create an HttpServletRequest and HttpServletResponse with default content as follows:


  import com.openbrace.obmimic.mimic.servlet.http.HttpServletRequestMimic;
  import com.openbrace.obmimic.mimic.servlet.http.HttpServletResponseMimic;
  import javax.servlet.http.HttpServletRequest;
  import javax.servlet.http.HttpServletResponse;

  ...

  HttpServletRequest request = new HttpServletRequestMimic();
  HttpServletResponse response = new HttpServletResponseMimic();

  ...
      

Note that as per 6.2 Servlet Contexts above, the resulting request and response will by default both have the same ServletContextMimic instance as their servlet context (specifically, the default ServletContextMimic instance).

7.2 Basic Example

In practice, you will usually want to configure one or more mimic instances for use in a particular test, then pass them to the code being tested, then check their resulting state.

To illustrate the basics of this, the following code shows a fairly minimal (and not necessarily typical) example that invokes an example HttpServlet with an HTTP “GET” request with a particular request parameter and an existing request attribute, after first initializing the servlet with a minimal/default ServletConfig instance. It then retrieves the response’s resulting status code and body content for subsequent checking.

Extensive commentary and notes are given below, to explain various details of the example, describe some of the possible alternatives at each step, and give a somewhat deeper insight into the relevant ObMimic facilities.


  import com.openbrace.obmimic.mimic.servlet.http.HttpServletRequestMimic;
  import com.openbrace.obmimic.mimic.servlet.http.HttpServletResponseMimic;
  import com.openbrace.obmimic.mimic.servlet.ServletConfigMimic;
  import javax.servlet.Servlet;
  import javax.servlet.ServletException;
  import java.io.IOException;

  ...

  /*
   * Create the request and configure it as needed by the test.
   * For additional commentary, see notes 1 and 2 below.
   */
  HttpServletRequestMimic request = new HttpServletRequestMimic();
  request.getMimicState().getRequestParameters().set("name", "mike");
  request.getMimicState().getAttributes().set("x", 1);

  /* Create the response. For additional commentary, see note 2 below. */
  HttpServletResponseMimic response = new HttpServletResponseMimic();

  /*
   * Create and initialize the servlet to be tested, using a dummy/minimal
   * ServletConfig. For additional commentary, see notes 3, 4, 5 and 6
   * below.
   */
  Servlet myServlet = new MyHttpServlet();
  try {
      myServlet.init(new ServletConfigMimic());
  } catch (ServletException e) {
      ... failed with unexpected ServletException ...
  }

  /*
   * Invoke the servlet to process the request and response.
   * For additional commentary, see note 6 below.
   */
  try {
      myServlet.service(request, response);
  } catch (ServletException e) {
      ... failed with unexpected ServletException ...
  } catch (IOException e) {
      ... failed with unexpected IOException ...
  }

  /*
   * Retrieve the response's resulting status code and body content, as
   * examples of how the resulting state of the relevant mimic instances
   * can be examined. For additional commentary, see notes 7, 8 and 9 below.
   */
  int statusCode = response.getMimicState().getHttpStatusCode();
  String bodyContent = response.getMimicState().getBodyContentAsString();

  ...
      

Additional commentary and notes:

  1. In this case we just want to set an example request parameter and an example attribute as a basic example of how a mimic’s internal state can be configured. We also want the request to be a “GET”, but that is the default anyway, so there’s no particular need to set it (though we could do so using request.getMimicState().setHttpMethodName("GET") if we wanted to). Note that there are many more details of the request that can be configured, and various helper classes and methods that can be used to assist in the setting of these details. Refer to the ObMimic Javadoc for full details.
  2. As per 6.2 Servlet Contexts above, by default a single default ServletContextMimic instance is used as the ServletContext for all requests and responses (and for any other mimics that need an associated ServletContext, such as the ServletConfigMimic used in this example). If necessary, this ServletContextMimic can be configured by retrieving it from the request or response by means of their mimicState’s getServletContext method, and then manipulating its own mimicState as desired. This default ServletContextMimic can also be accessed directly by means of the static getDefaultServletContext method of class com.openbrace.obmimic.mimic.servlet.ServletContextMimicFactory. However, you can also freely create and use other ServletContextMimics as desired (for example, wherever you want to use separate ServletContextMimic instances for separate tests), and you can specify the ServletContext to be used by each request and response by means of their mimicState’s setServletContext method. For this particular example, the default ServletContextMimic is used and no particular non-default configuration of its mimicState is required, so no code is necessary to specify or configure the ServletContext. In contrast, the ServletContext Example below illustrates the use of a separate explicitly-constructed ServletContextMimic, and its configuration to reflect particular deployment descriptor values and web-application resources.
  3. This example uses a class name of “MyHttpServlet” to represent the particular servlet class that is being tested. This is assumed to be a suitable servlet that supports the HTTP “GET” method (for example a javax.servlet.http.HttpServlet subclass with an override of the inherited “doGet” method), and to be suitably imported or otherwise accessible to this code.
  4. Depending on the servlet, calling its “init” method might not be strictly necessary, and ObMimic also provides various other ways to create and initialize servlets, but this is just included here as an example of explicitly initializing a servlet before using it. This example also uses the need for a ServletConfig instance to show an example of creating a mimic instance where we just need a non-null instance of a particular Servlet API interface but don’t care about its specific details.
  5. Theoretically we should also call the servlet’s “destroy” method when finished with it (ideally using a try/finally block). However, for the purposes of this example it is assumed that the servlet involved does not particularly need this, or that it is otherwise irrelevant to this particular test, and can therefore be omitted.
  6. The servlet’s “init” and “service” methods can potentially throw checked exceptions. Depending on the particular test framework being used and how you wish to treat such exceptions during your tests, you may wish to catch these (either at each point where they can occur or for the test as a whole) and report the unexpected failure in some way, or you may be happy to leave them to be caught and reported by the test framework. This example code shows them being explicitly caught at each point where they can occur simply in order to highlight their presence, but does not show any particular handling of them (which would typically use the relevant test framework’s facilities to report the failure of the test with some appropriate message).
  7. In practice this example code would be followed by checking the retrieved values in some way (for example using the relevant test framework’s “assert” facilities), but the details of this depends on the particular test framework you are using (or however else you deal with such checks and their possible failure), so is not shown in this example which instead just shows the relevant values being retrieved into local variables for subsequent checking.
  8. Another approach that can be used when checking the effects of a test on a mimic instance is to use the copyFrom and equals methods of the relevant MimicState class to create an “expected result” MimicState instance and compare the mimic’s actual mimicState against this after carrying out the test. Typically this involves creating an instance of the relevant MimicState class and using its copyFrom method to populate it with a copy of the relevant mimic’s mimicState after it has been configured but before carrying out the test. This can then be modified to reflect the expected effects of the test. Following the test, the two mimicStates can then be compared using their normal equals implementations. Compared to checking individual properties, this has the advantage of checking that only the expected changes have occurred and the rest of the instance’s internal state is unaffected (without having to check every property individually). On the other hand it has the disadvantage that if the comparison fails there is no indication of the specific property involved or its values. In addition, care is needed when using this approach to allow for all changes to the mimic’s mimicState, including any that might not be directly relevant to the particular test being carried out (and also including any automatic initialization or other such “state” changes made by ObMimic when using the mimic). Nevertheless, this can be a useful approach in some situations. For further details and example code, refer to the “How To” guides How to copy Mimics and their internal states and How to compare Mimics and their internal states.
  9. This example uses the getBodyContentAsString method of the response’s mimicState to retrieve the response’s body content as a string. This method interprets the body content’s bytes based on the response’s character encoding, as given by its mimicState’s “configuredCharacterEncoding” property. The response’s mimicState also provides a similar getBodyContentAsByteArray method for retrieving the response’s body content as a byte array. Note that both of these methods are provided as convenient shortcuts for the common requirement of retrieving the response’s body content, with the body content itself actually being captured by the mimicState’s underlying outputStream (which itself is a ServletOutputStreamMimic). Alternatively, or if more precise details of the output’s buffering and current state is required, it is equally possible to retrieve the underlying outputStream itself and examine its mimicState directly (as shown in the ServletContext Example below).

7.3 ServletContext Example

This example substantially extends the preceding Basic Example to illustrate the use of an explicitly-created ServletContextMimic and extensive configuration of this ServletContextMimic. It also illustrates the use of a number of additional features of ObMimic and some alternative approaches to the code shown in the preceding example. This includes:

  • The use of variables to hold references to MimicStates so as to simplify sequences of operations on them.
  • Configuration of various properties of the ServletContextMimic, including web-application “deployment descriptor” settings, web-application resources, and servlet-container details and behaviour.
  • Creation of a “paired” request and response.
  • Programmatic setting of ObMimic configuration properties, in this case to specify the use of a particular Servlet API version (and including the use of ObMimic’s PropertyNames class to help generate the relevant property name).
  • The use of the ServletContextMimic’s configuration to handle normal Servlet API request dispatching (and in particular the use of normal request “forwarding” as one of the possible ways to invoke the code that is to be tested), including the automatic initialization of the servlet context and the construction and initializing of servlets, filters and listeners as necessary.
  • Retrieval and examination of the underlying ServletOutputStreamMimic used as the response’s ServletOutputStream.

This is by no means intended to be comprehensive, but illustrates how some particular features of ObMimic can be used and gives a flavour of some of the facilities available.

Extensive commentary and notes are given below, to explain various details of the example, describe some of the possible alternatives at each step, and give a somewhat deeper insight into the relevant ObMimic facilities.


  import com.openbrace.obmimic.mimic.servlet.ServletContextMimic;
  import com.openbrace.obmimic.mimic.servlet.ServletOutputStreamMimic;
  import com.openbrace.obmimic.mimic.servlet.http.HttpServletRequestMimic;
  import com.openbrace.obmimic.mimic.servlet.http.HttpServletResponseMimic;
  import com.openbrace.obmimic.state.servlet.ServletContextState;
  import com.openbrace.obmimic.substate.servlet.ErrorPageMapping;
  import com.openbrace.obmimic.substate.servlet.FilterDefinition;
  import com.openbrace.obmimic.substate.servlet.FilterMapping;
  import com.openbrace.obmimic.substate.servlet.ListenerDefinition;
  import com.openbrace.obmimic.substate.servlet.ServletContainer;
  import com.openbrace.obmimic.substate.servlet.ServletDefinition;
  import com.openbrace.obmimic.substate.servlet.ServletMapping;
  import com.openbrace.obmimic.substate.servlet.WebAppConfig;
  import com.openbrace.obmimic.substate.servlet.WebAppResources;
  import com.openbrace.obmimic.support.servlet.DispatcherTypeEnum;
  import com.openbrace.obmimic.support.servlet.http.HttpRequestAndResponseMimicPair;
  import com.openbrace.obmimic.config.ObMimic;
  import com.openbrace.obmimic.config.PropertyNames;
  import com.openbrace.obmimic.api.ApiEnum;
  import com.openbrace.obmimic.api.ServletApiVersionEnum;
  import com.openbrace.obcommon.io.ReadableResource;
  import com.openbrace.obcommon.io.ByteArrayReadableResource;
  import com.openbrace.obcommon.io.SystemReadableResource;
  import javax.servlet.RequestDispatcher;
  import javax.servlet.ServletException;
  import java.io.IOException;

  ...

  /*
   * Create the ServletContext to be used and obtain its mimicState
   * for subsequent configuration. For additional commentary, see
   * note 1 below.
   */
  ServletContextMimic context = new ServletContextMimic();
  ServletContextState contextState = context.getMimicState();

  /*
   * Configure various basic properties of the ServletContext.
   */
  contextState.setContextPath("/myContext");
  contextState.getAttributes().set("contextAttributeA", 1);
  contextState.getAttributes().set("contextAttributeB", 2);

  /*
   * Configure the ServletContext's deployment descriptor details.
   * For additional commentary, see notes 1 and 2 below.
   */
  WebAppConfig webAppConfig = contextState.getWebAppConfig();
  webAppConfig.setDisplayName("My Web-App");
  webAppConfig.getContextParams().set("contextParmA", "1");
  FilterDefinition myFilterDefinition = new FilterDefinition();
  myFilterDefinition.setFilterName("myFilter");
  myFilterDefinition.setFilterClass(MyFilter.class.getName());
  myFilterDefinition.getInitParameters().set("foo", "x");
  myFilterDefinition.getInitParameters().set("bar", "y");
  webAppConfig.getFilterDefinitions().add(myFilterDefinition);
  FilterMapping myFilterMapping = new FilterMapping();
  myFilterMapping.setFilterName("myFilter");
  myFilterMapping.setUrlPattern("/x/*");
  myFilterMapping.getDispatcherTypes().add(DispatcherTypeEnum.REQUEST);
  myFilterMapping.getDispatcherTypes().add(DispatcherTypeEnum.FORWARD);
  webAppConfig.getFilterMappings().add(myFilterMapping);
  webAppConfig.getListenerDefinitions().add(
      new ListenerDefinition(MyListener.class.getName()));
  ServletDefinition myServletDefinition = new ServletDefinition();
  myServletDefinition.setServletName("myServlet");
  myServletDefinition.setServletClass(MyHttpServlet.class.getName());
  myServletDefinition.getInitParameters().set("foo", "x");
  myServletDefinition.getInitParameters().set("bar", "y");
  myServletDefinition.setLoadOnStartup(Integer.valueOf(5));
  webAppConfig.getServletDefinitions().add(myServletDefinition);
  ServletMapping myServletMapping = new ServletMapping();
  myServletMapping.setServletName("myServlet");
  myServletMapping.setUrlPattern("/x/y/*");
  webAppConfig.getServletMappings().add(myServletMapping);
  webAppConfig.getMimeTypes().setMimeTypeForExtension("html",
      "text/html");
  webAppConfig.getErrorPages().add(
      new ErrorPageMapping(404, null, "/err/notfound.html"));

  /*
   * Configure the ServletContext's static resources.
   * For additional commentary, see notes 1, 3, 4 and 5 below.
   */
  WebAppResources webAppResources = contextState.getWebAppResources();
  ReadableResource exampleInMemoryStaticResource
      = new ByteArrayReadableResource("Example content".getBytes());
  webAppResources.setResource("/static/example.txt",
      exampleInMemoryStaticResource);
  ReadableResource exampleClasspathResource
      = new SystemReadableResource("com/x/y/example.xml");
  webAppResources.setResource("/WEB-INF/myconfig.xml",
      exampleClasspathResource);

  /*
   * Configure the ServletContext's treatment of servlet-container and
   * environment-dependent details and behaviour. For additional
   * commentary, see notes 1 and 6 below.
   */
  ServletContainer container = contextState.getContainer();
  container.setServerInfo("Simulated Server/3.1");
  container.setDefaultResponseBufferSize(4096);
  container.setFileSeparator(false, "/");
  container.getBehaviour().setHttpServletRequestGetHeaderNamesProhibited(
      true);
  container.getBehaviour().setHttpServletRequestGetHeadersProhibited(
      true);

  /*
   * Create a request/response pair for the ServletContext. For additional
   * commentary, see notes 7 and 8 below.
   */
  HttpRequestAndResponseMimicPair requestAndResponse
      = new HttpRequestAndResponseMimicPair(context);
  HttpServletRequestMimic request = requestAndResponse.getRequest();
  HttpServletResponseMimic response = requestAndResponse.getResponse();

  /*
   * Configure the request as needed by the test. For additional
   * commentary, see note 9 below.
   */
  request.getMimicState().getRequestParameters().set("name", "mike");
  request.getMimicState().getAttributes().set("x", 1);

  /*
   * Explicitly set ObMimic to simulate Servlet API 2.4. For additional
   * commentary, see note 10 below.
   */
  String propertyName
      = PropertyNames.getApiVersionPropertyName(ApiEnum.SERVLET);
  ObMimic.setRuntimeOverride(propertyName,
      ServletApiVersionEnum.SERVLET_2_4.toString());

  /*
   * Use the normal Servlet API facilities to "forward" the request
   * and response to the servlet, using the ServletContext's configuration
   * to invoke the appropriate servlet together with any appropriate
   * filters and listeners, creating and initializing suitable instances
   * of these as necessary. For additional commentary, see notes 11, 12 and
   * 13 below.
   */
  RequestDispatcher dispatcher
     = context.getRequestDispatcher("/x/y/z.html");
  try {
      dispatcher.forward(request, response);
  } catch (ServletException e) {
      ... failed with unexpected ServletException ...
  } catch (IOException e) {
      ... failed with unexpected ServletException ...
  }

  /*
   * Retrieve the response's status code and various details from its
   * underlying OutputStreamMimic, as examples of how the resulting state
   * of the relevant mimic instances can be examined. For additional
   * commentary, see notes 14 and 15 below.
   */
  int statusCode = response.getMimicState().getHttpStatusCode();
  ServletOutputStreamMimic responseOutput
      = response.getMimicState().getOutputStream();
  boolean wasCommitted
      = responseOutput.getMimicState().isCommitted();
  boolean wasAutoCommitted
      = responseOutput.getMimicState().isAutoCommitCompleted();
  byte[] bodyContent
      = responseOutput.getMimicState().getAllBodyContent();

  ...
      

Additional commentary and notes:

  1. Each mimic instance retains the same mimicState instance throughout its lifetime, and in general the same applies to any MimicState subcomponents within the mimicState. It is thus safe to obtain a reference to a mimic’s mimicState and retain this in a variable for subsequent use. This example demonstrates this for the ServletContextMimic’s mimicState and various subcomponents within it.
  2. This example demonstrates the use of the webAppConfig property of the ServletContextMimic’s mimicState to configure the details of the servlet context’s web-application that correspond to its “deployment descriptor” settings. Whilst by no means comprehensive, this example demonstrates the use of the webAppConfig to configure a filter definition and filter mapping, a listener definition, a servlet definition and servlet mapping, a MIME-type mapping, an “error page” mapping, and some other miscellaneous settings (assuming the presence of suitable “MyServlet”, “MyFilter” and “MyListener” classes). For further details, refer to the “How To” guide How to simulate a web-application’s deployment-descriptor settings, and to the ObMimic Javadoc for the com.openbrace.obmimic.substate.servlet.WebAppConfig class and its subcomponents.
  3. This example demonstrates the use of the webAppResources property of the ServletContextMimic’s mimicState to configure the resources that are considered to be present at various context-relative paths within the web-application. This example configures two such resources. The first resource is configured at a context-relative path of “/static/example.txt”, with its contents provided by a ByteArrayReadableResource constructed from a byte array derived from a simple string literal. This approach allows the content of the resource to be supplied directly by the test code itself (though this example derives the byte array from the string using the string’s getBytes() method and thus uses the default character encoding, whereas in practice it would normally be better to use the getBytes(String) method and explicitly specify the character encoding to be used). The second resource is configured at a context-relative path of “/WEB-INF/myconfig.xml”, with its contents provided by a “com/x/y/example.xml” file that is read from the code’s classpath by means of a SystemResourceReadableResource. This approach allows the content of the resource to be supplied as a file alongside the test code’s class files (for example, by a file maintained within the test code’s source directory structure and copied across to the output directory structure when the test code is compiled).
  4. Although not shown in this example, ReadableResource implementations are also provided for accessing the contents of a file specified by its path/filename (optionally using a specified environment variable’s value as a path prefix, and recognizing a first path element of “~” as specifying the user’s “home” directory as given by Java’s “user.home” system property), and for retrieving the contents from a given URL.
  5. The WebAppResources class also supports loadResourcesFromDirectory methods that can be used to populate it from an entire directory structure (with one overload of this method that treats the specified directory structure as the root of the context’s resources, and another overload of this method that treats it as corresponding to a context-relative path within the context’s resources). For example, this could be used to populate the static resources from the root of an unzipped “war” archive or other such web-application directory structure (or a similar such structure containing only those particular contents that are needed by the test), or to populate the static resources under “/WEB-INF” from a specific directory. For further details, refer to the Javadoc for the WebAppResources class.
  6. This example demonstrates the use of the container property of the ServletContextMimic’s mimicState to configure various values and behaviour that are specific to each servlet-container or otherwise depend on the underlying environment. In particular, these settings can be used to control ObMimic’s behaviour where the Servlet API Javadoc allows different servlet containers to have different behaviour or leaves certain aspects of the container’s behaviour unspecified (for example, whether it allows the HttpServletRequest getHeaderNames and getHeaders methods to access the request’s headers, or instead treats these methods as prohibited such that they always return null). As usual, reasonable defaults are provided for all of these properties. For further details, refer to the Javadoc for the ServletContainer class and its ServletContainerBehaviour subcomponent. Note that each ServletContextMimic’s mimicState has its own independent container instance, so these settings can be configured separately for each ServletContextMimic.
  7. For most situations there is no particular need for the request and response to be created together or explicitly associated with each other. However, there are a number of situations (primarily related to forwarding of requests and HTTP session handling) where an HTTP request’s behaviour may depend on or update various details of the corresponding HTTP response and vice-versa. To support this, the HttpServletRequestMimic’s mimicState includes an associatedResponse property that can be explicitly set to specify the associated response, and the HttpServletResponseMimic’s mimicState includes an associatedRequest property that can be explicitly set to specify the associated request. Whilst these properties can be set individually, ObMimic also provides an HttpRequestAndResponseMimicPair class that can be used to construct and obtain an HttpServletRequestMimic and HttpServletResponseMimic that already have these properties set to refer to each other. This can also optionally set both of the resulting mimics to have a given ServletContextMimic as their servlet context. This example shows the use of this class to create such a request and response.
  8. Note that when an HttpServletRequestMimic and HttpServletResponseMimic are not explicitly “associated” with each other (as described above), ObMimic defaults to using other properties of the request’s mimicState to control what values it assumes for details of the response and vice-versa, such that all of the relevant values have suitable default values and can also be explicitly controlled individually. For full details, refer to the Javadoc for the HttpServletRequestState and HttpServletResponseState classes.
  9. In this case we just want to set an example request parameter and an example attribute as a basic example of how a mimic’s internal state can be configured. Note that there are many more details of the request that can be configured, and various helper classes and methods that can be used to assist in the setting of these details. Refer to the ObMimic Javadoc for full details.
  10. The actual property name used for specifying the Servlet API version to be simulated is “com.openbrace.obmimic.api.servlet.version”, and this could be used directly. However, the PropertyNames class provides constants and methods to assist in the formation of property names, and this example demonstrates the use of its getApiVersionPropertyName method to construct the appropriate property name. Note that setting this property to a non-default value is only permitted if a valid “Professional” or “Enterprise” licence is present. Note also that whilst this example shows this property being set programmatically within the test (and could, for example, easily be extended to repeat the test for different Servlet API versions), it is also possible to set this property for use throughout ObMimic via ObMimic’s configuration file or via a Java system property. Refer to the “How To” guides How to configure the Servlet API version to be simulated and How to set an ObMimic configuration property for further details.
  11. This example demonstrates the use of normal Servlet API request dispatching to forward to a context-relative path. For the given context-relative path, the ServletContextMimic’s configuration should result in the “myServlet” servlet being invoked after passing the request and response through the “myFilter” filter. ObMimic will initialize the servlet context and construct and initialize any relevant filter and servlet instances as necessary, and will construct and invoke the necessary FilterChain for the relevant filters and target servlet or static resource. This will include construction and notification of the servlet context’s listeners where appropriate. For Servlet API 2.5 onwards it will also include processing any “@PostConstruct” and “@Resource” annotations on the filters, servlets and listeners, using ObMimic’s built-in JNDI simulation where necessary. Similarly, any request dispatching or invocation of “error pages” carried out by the code being tested will be handled as appropriate based on the ServletContextMimic’s configuration.
  12. In comparison to the preceding Basic Example, the use of a RequestDispatcher “forward” to invoke the code to be tested allows the combined effect of the “myFilter” filter and “myServlet” servlet to be tested together, and avoids having to explicitly construct and initialize the filter and servlet instances. This is just shown here to illustrate one of several possible ways to achieve this, and to highlight ObMimic’s ability to handle normal Servlet API “request dispatching” based on the ServletContextMimic’s configuration. Such “forwarding” of the request and response may be convenient in some situations, but may be inappropriate in others. In particular, such Servlet API “forwarding” is not necessarily the same as processing the request when it has been received directly from the client (which can also be simulated by ObMimic). For example, under Servlet API 2.3 filters are never applied when forwarding, whilst for Servlet API 2.4 onwards this can be explicitly configured (and hence different filters may be applied when forwarding a request as opposed to processing it directly). As further alternatives, you can also use the FilterChainMimicFactory and FilterChainMimic classes to explicitly construct and invoke a filter chain with any required filters and a target servlet or static resource, or can use the static dispatch method of class com.openbrace.obmimic.support.servlet.DispatchingUtilities to carry out a “REQUEST”-type dispatch of a request and response to the appropriate filters and target servlet or static resource for any given context-relative path within a given ServletContextMimic. In addition, many of the classes and methods used internally by ObMimic can also be called directly and may be useful for invoking servlets and filters (for example, to construct and initialize a servlet given its class name and a suitable ServletConfig instance). For further details regarding request dispatching, refer to the “How To” guide How to handle request dispatching.
  13. The RequestDispatcher “forward” method can potentially throw checked exceptions.Depending on the particular test framework being used and how you wish to treat such exceptions during your tests, you may wish to catch these and report the unexpected failure in some way, or you may be happy to leave them to be caught and reported by the test framework. This example code shows them being explicitly caught simply in order to highlight their presence, but does not show any particular handling of them (which would typically use the relevant test framework’s facilities to report the failure of the test with some appropriate message).
  14. This example demonstrates the use of the outputStream property of the HttpServletResponseMimic’s mimicState to retrieve various details of the response’s output (in comparison with the preceding Basic Example, which uses its getBodyContentAsString method as a convenient way to retrieve the entire body content as a simple string).
  15. Each ServletResponseMimic and HttpServletResponseMimic uses a single ServletOutputStreamMimic to handle the body content written to its output, with this being accessible via its mimicState’s outputStream property. This is also used as the underlying output stream for any PrintWriter used by the response, such that it captures all of the response’s output regardless of whether it is written via the response’s “outputStream” (using its getOutputStream method) or via its “writer” (using its getWriter method).

7.4 Further Examples

Refer to ObMimic’s various How To guides for additional examples that show how to use particular ObMimic features (including code examples, discussion of various options and alternatives, and explanations of ObMimic’s internal operation).

8  Further Information

For further information, please refer to: