1  What is a “Mimic”?

A “mimic” is an object that can be used during testing in place of some real object that would normally be used by the code being tested, and which fully and accurately simulates that real object’s public API and functionality (that is, “mimics” the real object) whilst being more suitable for testing purposes than the real object.

The mimic’s simulation of the real object includes fully and accurately implementing the relevant interface or interfaces (or, for concrete classes, subclassing the relevant class and providing suitable implementations for its abstract methods and overrides for other methods where appropriate), though some non-functional characteristics of the real object (such as performance and scalability) may be sacrificed.

The additional facilities provided by the mimic to support testing may, for example, include any or all of:

  • Being suitable for use in test environments where the real object cannot be used or may not be suitable (for example, where the real object can only be instantiated and used within a servlet container or other such specific environment).
  • Providing more complete facilities for configuring the object’s state than is provided by the real object (for example, where the real object has read-only properties that cannot be configured via its public API).
  • Providing additional instrumentation for inspecting the object’s state and the calls made to its methods (for example, so that the sequence of API calls made to the object during a test can be examined).
  • Simulating or capturing data in-memory where the real object would use I/O facilities or other such slow or inconvenient external services.
  • Being configurable to simulate the real object’s behaviour in different environments or scenarios (for example, to simulate different versions of an API, or the presence or absence of “optional” facilities, or different values for environment-supplied configuration settings).
  • Being configurable to simulate different implementations of the real object (for example, where an API allows for a number of different implementation-specific behaviours, or where compatibility with some particular implementation’s non-standard behaviour must be tested).
  • Providing stricter validation of calls and method arguments than the real object, so that tests using the mimic automatically check for correct use of the object and provide clear error messages and “fail-fast” behaviour if used incorrectly, even where some or all real implementations are less strict or exhibit less clear-cut failure when used incorrectly.

In terms of the definitions given by Gerard Meszaros on the xUnit Patterns website (specifically, the definitions given on the Mocks, Fakes, Stubs and Dummies page and referenced from it), a “mimic” can be seen as a particular type of Test Double. It can be considered as most closely resembling a Fake, but with a somewhat different emphasis and with the potential to also support many of the features of other types of test doubles such as “Dummy Objects”, “Test Stubs”, “Test Spys”, and “Mock Objects”. In particular, in terms of the “Role Descriptions” table shown on Mocks, Fakes, Stubs and Dummies:

  • A mimic’s “purpose” potentially encompasses those of the other types of test doubles, but also includes supporting both “state-based” verification (as described in Martin Fowler’s excellent Mocks aren’t Stubs article) and larger-grained “integration” (multi-unit) tests.
  • A mimic “has behaviour”.
  • A mimic can “inject indirect inputs” into the system under test.
  • A mimic can “handle indirect outputs” from the system under test by capturing them for later verification and potentially also for verifying them against expectations (although the mimics provided by ObMimic do not currently implement any direct support for “expectations”).
  • A mimic’s “outputs” can optionally be provided by the tester.

In a sense, all types of “test double” aim to simulate the relevant real object whilst adding various additional facilities for use in testing. Each type of test double sacrifices some particular aspects of the real object’s behaviour in order to make the test double easier to develop, often to the extent that it can be automatically generated. The different approaches used to achieve this result is each type of test double having different capabilities and limitations, and being able to support a different subset of test-related facilities, and being suitable for some situations but not others. From this viewpoint, mimics can be seen as an extreme type of test double that makes no sacrifices in its simulation of the real object’s functionality. Instead, a mimic fully and accurately simulates the real object, and does not intrinsically preclude any of the potential additional test facilities.

The drawback to mimics is that providing a complete and accurate simulation of the real object together with extensive facilities to support testing generally makes the development of a mimic a substantial and non-trivial exercise (for example, the resulting mimic itself needs to be adequately tested). In general this makes the writing of mimics impractical for more general simulation of arbitrary objects and interfaces. However, for standard APIs that are widely used the effort required to centrally develop and maintain a suitable library of mimic classes may be justified, as the resulting mimics can then potentially be used by anyone testing code that involves that API.

Mimics can thus be regarded as providing a superset of the facilities provided by other types of test doubles, at the cost of requiring much greater development effort — they are what you’d ask for if someone else was providing you with custom-made test doubles with no effort on your part. Given a ready-made mimic that has already been written by somebody else, using it can often be simpler, more effective and useful for a wider variety of tests than using other types of test double (at least in our opinion).

2  What Mimics are Provided by ObMimic?

ObMimic provides a set of mimic classes for the Servlet API, including mimic implementations for every interface and abstract class of the Servlet API (for the currently supported Servlet API versions, namely 2.3, 2.4 and 2.5).

Specifically, mimic classes are provided for:

  • javax.servlet.Filter
  • javax.servlet.FilterChain
  • javax.servlet.FilterConfig
  • javax.servlet.RequestDispatcher
  • javax.servlet.Servlet (and javax.servlet.Servlet together with javax.servlet.SingleThreadModel)
  • javax.servlet.ServletConfig
  • javax.servlet.ServletContext
  • javax.servlet.ServletContextAttributeListener
  • javax.servlet.ServletContextListener
  • javax.servlet.ServletRequest
  • javax.servlet.ServletRequestAttributeListener
  • javax.servlet.ServletRequestListener
  • javax.servlet.ServletResponse
  • javax.servlet.SingleThreadModel
  • javax.servlet.GenericServlet (and javax.servlet.GenericServlet together with javax.servlet.SingleThreadModel)
  • javax.servlet.ServletInputStream
  • javax.servlet.ServletOutputStream
  • javax.servlet.http.HttpServletRequest
  • javax.servlet.http.HttpServletResponse
  • javax.servlet.http.HttpSession
  • javax.servlet.http.HttpSessionActivationListener
  • javax.servlet.http.HttpSessionAttributeListener
  • javax.servlet.http.HttpSessionBindingListener
  • javax.servlet.http.HttpSessionContext
  • javax.servlet.http.HttpSessionListener
  • javax.servlet.http.HttpServlet (and javax.servlet.http.HttpServlet together with javax.servlet.SingleThreadModel)

A mimic class is also provided for the java.security.Principal class, as this is needed internally within ObMimic.

Mimics are not currently provided for the Servlet API’s exception classes, “event” classes, and other simple concrete classes (such as javax.servlet.http.Cookie, javax.servlet.http.HttpUtils, and the request and response “wrapper” classes), on the basis that the concrete implementations of these classes provided by the API itself are adequate for use in testing. In particular, these classes provide adequate public constructors and methods to enable normal Java code to instantiate and configure instances as required, and there seems little need to provide additional test-only facilities for these classes. However, mimics for these classes may be introduced in future releases if this is found to be desirable.

Note that in addition to the mimic classes for the Servlet API (and their associated and supporting classes), ObMimic also provides a variety of related and supporting facilities including:

  • A basic in-memory JNDI simulation that can be used to support any JNDI look-ups of “java:” URIs from code being tested. Refer to the com.openbrace.obmimic.jndi package’s Javadoc for details.
  • Facilities for controlling the overall configuration of ObMimic (for example, which version of the Servlet API should be simulated), either globally via a properties file, or via the system properties for a particular run, or programmatically during individual tests. Refer to ObMimic’s configuration file (normally the “config.properties” file in the ObMimic installation’s /config directory) and the com.openbrace.obmimic.config.ObMimic class’s Javadoc for details.
  • A variety of utility classes and facilities which are used within ObMimic but may also be of more general use (for example, classes and methods for order-insensitive comparison of arrays; a thread-safe wrapper around java.text.SimpleDateFormat with additional convenience methods; a ReadableResource interface to represent any type of resource from which an InputStream can be obtained together with implementations for byte-arrays, classpath resources, URLs, and files, and for concatenating or prioritizing multiple such resources; and many other such facilities). Refer to the Javadoc for the various com.openbrace.obcommon packages for details.

3  What Facilities are Provided by ObMimic’s mimics?

ObMimic’s mimic classes all provide the following features and facilities:

  • Each mimic class provides a public no-argument constructor. Note that these initialize the resulting instance with appropriate default values and example content.
  • Each mimic class implements the relevant Servlet API interface(s) or extends the relevant Servlet API abstract class, and also implements the com.openbrace.obmimic.core.Mimic interface.
  • Each mimic instance has a getMimicState method that returns an instance of a corresponding class that implements the com.openbrace.obmimic.core.MimicState interface and represents and encapsulates the Servlet API object’s logical “internal state” (and which may in turn contain subcomponents that themselves implement the MimicState interface). Each mimic instance has a single such MimicState object which it retains throughout its lifetime and which is not shared with other mimics. This MimicState object can be used to configure and inspect the logical state of the mimic, independently of its Servlet API methods. For example, the Servlet API might define several methods for read-only access to a single underlying value in different formats or in combination with other data, for which the MimicState might provide a single property for the underlying value with simple “setter” and “getter” methods (with the mimic itself containing only the Servlet API methods, and the MimicState containing only the “setter” and “getter”). Each mimic class’s Javadoc specifies precisely how each of its Servlet API methods interacts with the MimicState and its subcomponents (that is, how the mimic’s implementation of the Servlet API method uses and where relevant updates its MimicState).
  • Some of ObMimic’s mimic classes can optionally “wrap” other instances of the relevant Servlet API class so as to provide the usual ObMimic configuration and instrumentation facilities whilst also forwarding the calls to some other instance for its own custom processing. In particular, ObMimic’s mimics for the Servlet API’s various listener interfaces and the Servlet, GenericServlet and Filter interfaces support this facility (via a chainedXxxxx property in their MimicState). For example, ObMimic’s GenericServletMimic supports all the usual ObMimic facilities and has a MimicState that tracks the number of calls to the various GenericServlet methods, but can optionally also forward the GenericServlet calls to any other Servlet instance that has been configured in its MimicState’s chainedServlet property.
  • Where the Servlet API methods can throw ServletExceptions, IOExceptions or other checked exceptions, the Mimic’s MimicState includes properties that can be used to force the Mimic’s methods to throw the relevant exception (in particular, to support testing of any code that catches the exception).
  • Each mimic instance has a getMimicHistory method that returns a com.openbrace.obcommon.history.ObjectHistory instance that can be used to record and examine the calls made to the mimic’s Servlet API methods. This recording of Servlet API calls can be programmatically turned on and off for individual mimic instances. The details recorded include the arguments passed to each call, the outcome of the call, and a unique sequence ID (across all Mimics) that shows the order in which each recorded API call occurred. Immutable representations are used for all API arguments and return values captured by such history recording, such that the recorded history is unaffected by any subsequent operations on those objects (and note that client code can potentially control how different types of object are encoded into immutable representations if the built-in default mechanism is not suitable). However, note that the use of these facilities is restricted to the “Professional” and “Enterprise” editions (that is, a “Professional” or “Enterprise” licence is required).
  • Each mimic instance has a getMimicListeners method that returns a com.openbrace.obmimic.core.MimicListeners instance. Listeners of type com.openbrace.obcommon.lang.MethodInvocationListener and com.openbrace.obcommon.lang.MethodExitListener can be installed into this to examine and optionally modify the calls made to the mimic’s Servlet API methods and their results, at the point that each such call occurs. As well as providing an alternative to the use of the mimic’s MimicHistory to examine the details of Servlet API calls in situations where the use of a listener may be more convenient, this also allows for the modification of such calls and their results wherever this might be necessary (for example, if you consider the ObMimic implementation of a Servlet API method to be incorrect in particular circumstances, or otherwise need to force or simulate a particular reply from a Servlet API method call and cannot achieve this via ObMimic’s normal configuration facilities). However, note that the use of these facilities is restricted to the “Professional” and “Enterprise” editions (that is, a “Professional” or “Enterprise” licence is required).

In addition:

  • Each mimic class has a matching “Factory” class (in the same package as the mimic class itself) with static methods through which instances of the mimic class can be created with given values for various properties (as a shortcut for constructing the instance and then individually populating the relevant properties of the instance’s MimicState).
  • The com.openbrace.obmimic.mimic.servlet.ServletContextMimicFactory class provides a singleton ServletContextMimic instance that is used by all relevant Mimics as their default ServletContext.
  • Where relevant, mimic classes also have a corresponding “Manager” class (in the relevant com.openbrace.obmimic.lifecycle.* package) that can be used to wrap an instance of the mimic class with additional methods for manipulating the mimic instance’s life-cycle or other such behaviour that is relevant to the use of the instance but is not explicitly provided by the Servlet API itself (for example, to explicitly “initialize” or “destroy” a ServletContextMimic, including issuing the appropriate calls to any relevant event-listeners).

Note that:

  • Where a mimic is for an abstract class, the mimic provides implementations for the abstract class’s abstract methods, and may optionally provide implementations for some or all of its other methods as necessary. A separate interface is defined for each such mimic class to identify the precise set of methods whose implementations are provided by the mimic. The remainder of the abstract class’s method implementations are inherited unchanged by the mimic (that is, the mimic uses the underlying Servlet API class’s normal/built-in implementation).
  • All MimicStates and their subcomponents are initialized with appropriate default/example values (as documented in their Javadoc) and provide a reset method that resets the instance to its initial values, a copyFrom method that populates the instance with the current content of another instance, and an appropriate equals implementation for comparison of instances. In particular, this allows the copying of internal state between Mimics, retention of copies of a Mimic’s internal state taken at various points in time, and comparison of a Mimic’s internal state against an “expected” state. For example, this makes it possible to configure a Mimic as necessary in preparation for a test, take a copy of its MimicState at that point, modify the copied MimicState to reflect the expected effects of the test, and then run the test and compare the Mimic’s resulting MimicState against the expected state.

4  Why use Mimics rather than Mocks, Stubs or Other Types of “Test Doubles”?

“Mocks”, “stubs”, “fakes”, “dummies” and other types of “test double” each have different capabilities and limitations, and each require different degrees of effort to develop and use.

Mimics normally require a substantial amount of development effort, so writing your own mimics for arbitrary APIs and application-specific classes isn’t normally worthwhile. However, where the necessary mimics are already provided for you by somebody else (such as ObMimic’s Servlet API mimics), using them can give you a comprehensive set of facilities for minimal effort. Using an already-written mimic provided by somebody else gives you a complete, independently developed, test-friendly implementation that replicates the complete behaviour of the “real” object together with additional test-related functionality and instrumentation — all without having to write any of this code yourself. Such a mimic can be used wherever you would otherwise need to write or generate a dummy, stub, fake, or other such test double, but can also address more complex requirements.

At its simplest, if you just need an object of the correct kind but don’t care about its state or behaviour, using an existing mimic for this can be as simple as invoking a normal no-argument constructor. If such a test later evolves to have more demanding requirements, the existing mimic then already includes all of the necessary facilities to support this.

More generally, mimics are especially useful where the “real” object has non-trivial behaviour, complex interactions between its methods (for example, where determining the details of a sequence of calls to various methods requires both a detailed knowledge of the code being tested and an accurate understanding of the precise behaviour of the individual methods), or complex interactions with other objects, libraries and frameworks. This is true both for “unit testing” of a single application class in isolation, and for larger-grained testing of the combined behaviour of multiple classes in combination with an underlying API or framework (for example, for out-of-container testing of complete JSF pages, as described in the “How To” guide How to test JSF pages).

In comparison to mock objects, mimics address a somewhat different set of requirements and suit a somewhat different style of testing, although in principle they could also be used for the same purposes as mock objects. Note that Martin Fowler’s Mocks aren’t Stubs article gives a good general discussion of mock objects, the differences between mocks and other types of test doubles, and the different styles of testing that result. In particular, mock objects support isolated, “interaction-based” testing of a class on its own, based on your own expectation of precisely what calls it should be making to other objects and the results you expect it to see for each such call. However, this isn’t so useful when want to:

  • Test code against the actual behaviour of a complex API or other classes (rather than just how you believe they ought to behave).
  • Test a complex sequence of calls that affect each other, such as when one call sets a value that is then used or returned by a later call (where a proper implementation might handle the sequence of calls correctly with little or no additional set-up, but a mock object implementation requires you to predict and configure all arguments and return values of each individual method).
  • You want to test the overall effect of the code being tested, rather than checking exactly what calls it uses to achieve that effect (which tends to result in “brittle” tests that are vulnerable to changes in the code’s internal implementation).
  • You want to test code that depends on third-party library/framework code that you can’t avoid (for example because it is your code’s superclass) and whose calls to the relevant API are outside of your control.

In all of these cases, you may find the use of mimics more suitable. Such cases often arise for code that uses or otherwise depends on the Servlet API and other such complex, “container”-implemented APIs.

In addition, although this is largely a matter of personal taste, you may also find that the structure of tests is clearer and more intuitive with mimics rather than mock objects. Tests using mimics can configure the mimics, then run the test, and then check that the mimics and other objects have the expected state. This is arguably a somewhat more natural and intuitive style than the “expectation”-based approach that has become synonymous with mock objects (where the mock objects are first informed of the calls they should expect and the results that each call should return, then the test is carried out, then the mock objects themselves check that they received the expected calls — with both initialization data and expected result values thus appearing together ahead of the code that actually runs the test).

Of course, there’s nothing to stop you mixing mimics and other types of test double as you see fit. For example, you can use ObMimic’s Mimics as test doubles for Servlet API objects whilst using mocks or stubs as test doubles for application-specific objects or other APIs. Similarly there is nothing to stop you using mimics in some tests and other types of test double in other tests.

5  What Types of Testing can ObMimic be used for?

ObMimic is intended for use in “out-of-container” testing of the functionality of code that uses the Servlet API, but is entirely agnostic as to the nature and granularity of the tests in which it is used. It can be used not only for “unit testing” of individual classes in isolation, but also for larger-grained tests of combinations of classes.

This potentially includes “out-of-container” tests of complete paths through an application, including any use of underlying library or framework code that this might involve. 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).

However, ObMimic is not intended for use within servlet containers, nor is it currently intended for multi-threaded use. In general it is thus not suitable for use in testing an application’s thread-safety, performance or scalability, nor in any “end-to-end” testing of a system as a whole (for example, checking an application’s integration into its intended run-time environment, its correct configuration and deployment, user-acceptance testing etc). It can, however, simplify such tests by allowing the detailed behaviour of the application code to be tested separately such that overall system/integration tests can then focus on the relevant issues.

6  Which Test Frameworks can ObMimic be used with?

ObMimic provides a set of plain-Java mimics and supporting classes for use within your tests, but these have no dependency on any particular test framework. ObMimic can thus be used in conjunction with any version of JUnit, any version of TestNG, or any other test framework that you are using — or even within arbitrary test classes of your own.

Note that the source code supplied with the “Enterprise” edition of ObMimic does include a full set of JUnit test cases for ObMimic’s own code, and compilation and testing of the ObMimic source code therefore depends on JUnit, but this does not affect the use of the compiled ObMimic jar archive.

7  Why Does a JDK/JavaEE Javadoc Link Show a Blank Page?

If you see a blank page when you follow a link from ObMimic’s Javadoc to a JDK, JavaEE or other external Javadoc page, this may be due to your security settings or security software blocking the opening of such pages within a current page’s “frame”.

Specifically, when Javadoc is being viewed in its usual “FRAMES” layout, links to external Javadoc attempt to open the linked-to document within the main Javadoc frame of the current page. Depending on the configuration of your browser and any proxy-server or other security software that you use, you may find that such attempts to open pages from another site within an existing frame are blocked, and result in an empty frame or a prompt or warning of some kind.

If this affects you and you do not want to (or cannot) remove the relevant restrictions, you can use the following alternatives to follow the links to the external Javadoc:

  • Open the linked-to page in a separate window or browser tab of its own.
  • Switch to the “no frames” version of the Javadoc via the “NO FRAMES” link in the header and footer of each Javadoc page.

8  Why Does Downloading Fail on MSIE?

If you are using Microsoft Internet Explorer® and an attempted download of a file from the OpenBrace website fails with no otherwise-apparent reason, please check that MSIE’s “Do not save encrypted pages to disk” option is turned off. If this option is turned on, MSIE 9 is generally unable to download files over HTTPS. This is also believed to apply to at least some other versions of MSIE (under at least some circumstances).

On MS Windows 7 you can find this setting within “Internet Options”, in the “Advanced” tab’s “Security” section.

For an explanation and more complete details, refer to Microsoft Knowledge Base articles 2549423 (for MSIE 9) and 812935 (for MSIE 8 and earlier).

9  Which JDKs has ObMimic been tested against?

Each release of ObMimic’s Community/Professional Editon is tested by running a comprehensive suite of extensive and detailed tests of all of its code on a number of different JREs on an MS Windows system and on a Linux system.

For the Enterprise Edition of ObMimic, a full run of the Enterprise Edition’s built-in build script (which itself includes running ObMimic’s full set of tests) is carried out on a number of suitable JDKs on an MS Windows system and on a Linux system. The resulting deliverables from each such build are then tested on the same system against the various JREs as per the normal Community/Professional Editon.

The current release of the Community/Professional Edition of ObMimic has been tested against the following JDKs:

  • Oracle Java SE 8 on MS Windows 7 and Linux.
  • Oracle Java SE 7 on MS Windows 7 and Linux.
  • Oracle Java SE 6 on MS Windows 7 and Linux.
  • Oracle Java SE 5 on MS Windows 7 and Linux.
  • IBM Java SE 7 on Linux.
  • IBM Java SE 6 on Linux.
  • IBM Java SE 5 on Linux.
  • Oracle JRockit 6 (version R27.3.1) on MS Windows 7 and Linux.
  • Oracle JRockit 5 (version R27.3.1) on MS Windows 7 and Linux.

The current release of ObMimic’s Enterprise Edition has been tested on the following JDKs (with each of the resulting customized ObMimic deliverables then tested against the JDKs listed above for the Community/Professional Edition):

  • Oracle Java SE 8 on MS Windows 7 and Linux.
  • Oracle Java SE 7 on MS Windows 7 and Linux.
  • IBM Java SE 7 on Linux.

10  Why do I get an UnacceptableApiJarException?

An UnacceptableApiJarException is thrown if ObMimic detects whilst constructing a Mimic or MimicState that the Servlet API classes on the classpath are unsuitable for use at run-time. You will typically need to use a different Java EE API jar or Servlet API jar to provide the Servlet API to your test runs.

In particular, as of late 2013 the javaee-api-*.jar and javaee-web-api-*.jar files available for download from within http://download.java.net/glassfish/4.0/promoted/ and from within http://mvnrepository.com/artifact/javax/ (and potentially from other Maven repositories, and identified by a groupId of “javax” and artifactIds of “javaee-api” and “javaee-web-api”) are specifically and deliberately intended only for compiling against, and do not support any run-time use. This is apparently due to rules for API jar files given by the Glassfish Wiki’s Maven Versioning Rules.

The class files provided by such API jar archives contain code that uses resources that have been deliberately omitted from the API jar archive. For example, some of the javax.servlet classes within these jar archives include code that loads a “LocalStrings” resource bundle during the loading and initialisation of the class, but the properties files for this resource bundle have been deliberately excluded from the jar archive. Any attempt to use these javax.servlet classes at run-time will thus result in an ExceptionInInitializerError (unless the necessary properties files are provided separately, for example by also having a different and more complete Servlet API jar archive on the classpath).

As the various exceptions that can result from this can be quite technical and unclear, ObMimic attempts to check for such jars as early as it can and throws an explicit “UnacceptableApiJarException” if the Servlet API is being provided by a jar that suffers from these limitations and cannot be used at run-time, so as to directly and clearly indicate this.

In practice ObMimic currently checks for this whenever a Mimic or MimicState instance is created. Its does this by trying to load one of the javax.servlet classes that throw exceptions when loaded from these jars and seeing if this results in the specific exceptions known to result from this problem. Note that at worst this might fail to detect an unsuitable jar that fails in unexpected ways (for example, if the internal code within such jars changes significantly in future releases), or if some other use is made of the Servlet API prior to constructing any Mimic or MimicState. In either case, if ObMimic fails to give an immediate and clear UnacceptableApiJarException then some internal exception from within the jar archive’s own code will typically be encountered at some other point during test runs. However, in most cases the ObMimic checks should result in a clear and immediate indication if the Servlet API classes are being supplied from an unsuitable jar archive.

If you see an UnacceptableApiJarException, you should examine the class path being used when running tests with ObMimic and change the jar that is supplying the Servlet API to one that is suitable for use at run-time (or retain the existing classpath but add a suitable jar onto the end of it to ensure that any files missing from the existing jar can be obtained from the additional jar).

As of late 2013, any jar for the Servlet API on its own should be suitable for use with ObMimic (for example, any servlet-api-*.jar), as should any complete Java EE jar taken from an application server or web-container (for example, the javaee.jar within a Glassfish installation).

11  Why do I get an ExceptionInInitializerError?

If you get an ExceptionInInitializerError from ObMimic code and the stack trace shows this being thrown by a javax.servlet class, this typically indicates the use of an unsuitable jar to supply the Servlet API, as described above for 10  Why to I get an UnacceptableApiJarException?.

ObMimic attempts to identify such situations and throw a more explicit indication of the problem (the aforementioned UnacceptableApiJarException), but if any of these unsuitable jars elude detection by ObMimic then their own code will typically fail at some point with some other exception whose cause might not be so obvious. For the jars currently known to be unsuitable, this will typically be an ExceptionInInitializerError (for example, due to attempting to load the ServletInputStream or ServletOutputStream classes but with the jar not containing the LocalStrings resource bundle that these classes load during their initialization).

12  What can I do if I need different Servlet API behaviour?

ObMimic attempts to provide a comprehensive and accurate implementation of each Servlet API method, based on a strict interpretation of the Servlet API Javadoc. To support this, its MimicState classes and overall configuration options attempt to cater for simulating any valid Servlet API behaviour, even where this may vary between Servlet implementations. Similarly, whilst ObMimic by default rejects Servlet API calls for which the Servlet API is ambiguous and the call might not be valid or its behaviour is not adequately specified, the “Professional” and “Enterprise” editions allow you to configure ObMimic’s behaviour for such calls.

You should therefore be able to obtain any valid Servlet API behaviour that you require, subject to possibly needing the “Professional” or “Enterprise” edition in order to support the necessary configuration.

However, it remains possible that you might encounter situations in which you need some specific behaviour from a Servlet API call and find that you cannot configure ObMimic to provide the desired behaviour. Examples of this could include:

  • Where you believe that the ObMimic behaviour is incorrect or incomplete (for example, due to a known bug that has not yet been fixed).
  • Where the code you are testing is internally using third-party code that you cannot change but that makes invalid or questionable calls to the Servlet API and depends on some particular non-standard behaviour that ObMimic is unable to provide. As an example, at least one JSF implementation has been known to call the ServletContext “getResource” method for a “directory” path, despite the Servlet API not stating whether such paths are legal for this method or how they should be treated. Although ObMimic has since been updated to cater for this particular situation, that was not the case when this call from a JSF implementation was first encountered, and other such situations might arise in other code.

Ideally, we’d like to hear about any such situations that you encounter, so that we can improve ObMimic to handle them. You can report any such problems using the relevant ObMimic discussion forum or via any of the other support mechanisms described on the Support.html page or our website’s Contact Us page.

However, if you don”t wish to report such situations or need a work-around in the meantime, there are a number of ways in which you can change how ObMimic responds to particular Servlet API calls.

The simplest and recommended way to do this is to use the “mimicListeners” facilities on each Mimic to intercept the relevant Servlet API call. These facilities are available in the “Professional” and “Enterprise” edition, and give you the ability to install listeners into the Mimic instance. These listeners are then notified of each Servlet API call on that mimic and its result. You can use such listeners to examine the details of each Servlet API call to the mimic and where necessary modify the arguments passed to the Servlet API method and/or the results returned by it. This should allow you to simulate any Servlet API behaviour that you require — at worst you can change the method arguments to values that ObMimic will treat as valid, and change the outcome of the call to be whatever result you require.

For full details of the “mimicListeners” facilities, including some example code, refer to the “How To” guide How to intercept, examine and modify the Servlet API calls to a Mimic and the Javadoc for the com.openbrace.obmimic.core.MimicListeners, com.openbrace.obcommon.lang.MethodInvocationListener and com.openbrace.obcommon.lang.MethodExitListener classes.

Another alternative, if you want to carry out more extensive customisation of ObMimic, would be to subclass the relevant ObMimic classes. This involves subclassing the MimicBody class that provides ObMimic’s implementation of the relevant Servlet API method (and if necessary, the MimicState class that it uses), and then subclassing the relevant Mimic class to use your new MimicBody subclass instead of its normal MimicBody class. You can then override the relevant Servlet API method implementation in your new MimicBody subclass so that it provides the desired behaviour (typically by means of suitable code before and/or after a call to the inherited existing implementation, and making appropriate use of the MimicState class where necessary). However, this requires some degree of understanding of how to construct instances of your MimicBody subclass so that it uses the relevant MimicState class, and how to construct and initialise instances of your Mimic subclass so that it uses your MimicBody subclass and implements the correct set of interfaces for the correct API. Whilst you may be able to figure out how to do this from ObMimic’s Javadoc, if you wish to go down this route we would recommend the use of the “Enterprise” edition so that you can view ObMimic’s source code and examine how this is done in the existing Mimic classes.

You could, of course, simply subclass the Mimic class on its own and override the relevant Servlet API method of the Mimic class, but any calls to that method which do not go through the inherited/normal ObMimic implementation will then not be subject to ObMimic’s “history” facilities, detection of deprecated/unavailable API methods for each Servlet API version, or any other such ObMimic facilities. This might, however, be sufficient if you just need to return some particular result from a specific type of call, whilst continuing to use the inherited implementation for all other calls.

With the “Enterprise” edition, you also have the option of simply making any changes directly within ObMimic’s internal code — though you will then need to consider any broader impact on ObMimic’s behaviour, and how to maintain the customised code when updating ObMimic to a new release.