Updated May 2013: ObMimic is now available from www.openbrace.com
At long last I’ve reached the stage where I can “eat my own dogfood” and use my ObMimic library for out-of-container testing of servlet code, so I’ve been trying it out on some existing applications.
But to start with, I guess I’d better explain just what “ObMimic” is, as I’ve not said anything much about it publicly yet.
So this article introduces ObMimic, and will be followed shortly by another one explaining some findings from my own initial use of it.
ObMimic is an as-yet-unreleased library of classes that supports “out of container” testing of code that depends on the Servlet API, by providing a complete set of fully-configurable POJO implementations of all of the Servlet API’s interfaces and abstract classes.
For every interface and abstract class of the Servlet API, ObMimic provides a concrete class (with a simple no-argument constructor) that is a complete and accurate simulation of the relevant Servlet API interface or class, based on an “internal state” object through which you can configure and query all of the relevant details.
This lets you test servlets, filters, listeners, and any other code that depends on the Servlet API (including, at least to some extent, higher-level frameworks that run on top of it), in the same way as you would for “plain” Java code. Typically, you construct and configure the Servlet API objects you need, pass them to the code being tested, and examine the results – with no need for any servlet containers, deployment, networking overheads, or complex “in-container” test frameworks.
Compared to HTTP-based “end-to-end” tests, this supports finer-grained and faster tests, and makes it far easier to test the effect of different deployment-descriptor values such as “init parameters” (because the relevant details can be changed at any time via normal “setter” methods, instead of requiring changes to the web.xml file and redeployment). You can also readily use ObMimic with JUnit, TestNG or any other test framework, as it doesn’t depend on any special base-class for tests and is entirely orthogonal to any test-framework facilities.
This approach is similar to using mocks or stubs for the Servlet API classes, but unlike mocks or stubs, ObMimic provides ready-made, complete and accurate implementations of the Servlet API functionality as defined by the Servlet API’s Javadoc. This includes proper handling of features such as request-dispatching, session-handling, listener notifications, automatic “commit” of responses when their specified content-length is reached, servlet and filter mapping, access to static resources at context-relative paths, merging of HTTP “POST” body-content and query-string request parameters, the effects of different sequences of Servlet API method calls, and all the other myriad and complex interactions between different Servlet API methods.
I call these implementation classes “mimics” in order to distinguish them from “mocks” and “stubs” and on the basis that they “mimic” the behaviour of real Servlet API implementations. Technically, they are “fake” objects as described by xUnit Patterns and Martin Fowler, with the addition of some stub/mock-like facilities. But the term “fake” doesn’t quite feel right, doesn’t seem to be very widely used, and some people use it as a synonym for “stub” (for example, Wikipedia as at the time of writing). Inventing yet another term isn’t ideal either, but at least it shouldn’t lead to any pre-conceptions or confusion with anything else.
Whilst mocks and stubs are fine for “interaction-based” testing or for arbitrary interfaces for which you don’t have “real” implementations, using “mimic” implementations seems a simpler, more natural and more useful approach for “state-based” testing or when you have access to appropriate “mimic” classes. At least, that’s my personal take on it. For a broader discussion of some of the relevant issues, see Martin Fowler’s article Mocks Aren’t Stubs.
By way of an example, at its simplest ObMimic lets you write test-case code like the following (where everything uses a “default” ServletContextMimic as the relevant ServletContext, and all details not explicitly configured start out with reasonable default values, such as the request being a “GET”):
HttpServletRequestMimic request = new HttpServletRequestMimic(); HttpServletResponseMimic response = new HttpServletResponseMimic(); request.getMimicState().getRequestParameters().set("a", "1"); // just for example Servlet myServlet = new SomeExampleServletClass(); myServlet.init(new ServletConfigMimic()); myServlet.service(request, response); // ... check contents of request, response etc...
Actually, the very simplest example is that if you just need, say, a ServletContext to pass as an argument to some method but its content doesn’t matter, you can just do “new ServletContextMimic()” – which must be about as simple as this could ever be.
ObMimic is also potentially usable for higher-level frameworks that run on top of the Servlet API, such as Struts. Such frameworks generally just need a suitably configured ServletContext and the relevant servlet/filter/listener definitions and mappings, plus various configuration files as static resources within the context – all of which are supported by ObMimic’s ServletContextMimic. And in many cases you can test components without needing the whole framework anyway – just requests and responses together with framework components that are themselves POJOs or otherwise suitably configurable. That’s the theory anyway. In practice this will depend on the details of the particular framework and the nature of its own classes and other API dependencies. But more of that in the next article…
Other current features of ObMimic include:
- Configurability to simulate different Servlet API versions (2.3, 2.4 or 2.5).
- A “mimic history” feature for recording and inspecting the Servlet API calls made to individual mimics.
- Explicit checking and control over the many ambiguities in the Servlet API. That is, where the Servlet API Javadoc is ambiguous about how a particular argument value or sequence of calls should be treated, the ObMimic Javadoc documents the ambiguity and by default ObMimic throws an exception if the code being tested issues such a call, but can also be configured to ignore the call, throw a specified exception, or ignore the ambiguity and process the call in some “reasonable” manner.
- A basic “in memory” JNDI simulation to support JNDI look-ups by the code being tested.
- Easy to add to projects, as it consists of a single jar archive with no dependences other than Java 5 or higher and the Servlet API itself (which the code being tested will already need anyway).
Features not yet present but intended for future versions include:
- Mimics for the JSP API, to support “out-of-container” testing of JSP pages, tag handlers etc.
- Population of ServletContextMimics from web.xml deployment descriptors.
- Population of HttpServletRequestMimics from the text of HTTP requests.
- Production of HTTP response texts from HttpServletResponseMimics.
- Specific support for particular web-frameworks (depending on demand and any particular issues encountered).
I guess I’ll be writing a lot more about these and other features over the next few months.
Anyway, the ObMimic code has been fully tested during its development, and has certainly been useful during its own testing. However, it’s in the nature of the Servlet API that any non-trivial code tends to depend on a large subset of the API and the interactions between its classes. So it hasn’t seemed particularly worth trying out ObMimic on any “real” projects whilst it was incomplete.
Now that ObMimic has reached the stage where it covers the entire Servlet API, I’ve finally been able to take it for a spin and try it out on some previously-written code. In particular, I’m keen to see how it copes with framework such as Struts, as this is likely to be a good way to shake out any problems.
So the next article will look at my initial experiences with using ObMimic to test some existing filters, listeners, Struts components, and overall Struts 1 operation (including out-of-container execution of the Struts 1 “ActionServlet” controller). I hope to follow this with further articles as I try it out for other web-frameworks, and progress towards a beta-test and public release.
By the way, in case you were wondering, the “Ob” in “ObMimic” is based on our not-yet-officially-announced company name.