In hypothetical scenario, let one of such differences between functional test environment and production environment be non-existence of application server. One might argue that it's slow and tedious to deploy application into application server every time which does slow down the continuous build. Another might argue that abstracting away from the environment that application server provides and enforces upon is simply too labour intensive. While QAs simply not happy with risk exposed from possibly not testing the integration point between application and application server, and anything that falls off the boundary of application. This sounds like a good place to get everyone talking. It might turn out that QAs are convinced that one or two integration tests are going to be ok given that the nature of integration is indifferent across the few integration points. However the discussion turns out to end, important thing is that everyone should have shared understanding at the end.
Whether by accident or common desire, there have been some efforts from open source communities to abstract away from existing servlet interface with relatively new Java API for RESTful web services. Most of the available implementations have an adaptor that bridges between servlet (i.e. an existing application server environment) and their own abstraction. This makes it a reasonable platform to write out-of container functional tests driven by HtmlUnitDriver with modified WebClient to intercept outgoing request to application.
public class OutOfContainerHtmlUnitDriver extends HtmlUnitDriver { private final InternalRequestDispatcher dispatcher; private final ResponseHandler responseHandler; private final List stubbedExternalResources; @Inject public OutOfContainerHtmlUnitDriver(InternalRequestDispatcher dispatcher, List stubbedExternalResources) { this.dispatcher = dispatcher; this.stubbedExternalResources = stubbedExternalResources; this.responseHandler = new ResponseHandler(); } @Override protected WebClient modifyWebClient(WebClient client) { new WebConnectionWrapper(client) { @Override public WebResponse getResponse(WebRequestSettings request) throws IOException { try { if (dispatcher.isInternalRequest(request.getUrl().toURI())) { StopWatch stopWatch = new StopWatch(); stopWatch.start(); Response response = dispatcher.dispatch(new HtmlUnitRequestAdaptee(request)); stopWatch.stop(); return new WebResponseImpl( responseHandler.webResponseData(response), responseHandler.charset(response), request, stopWatch.getTime()); } else { for (StubbedExternalResource stubbedExternalResource : stubbedExternalResources) { if(stubbedExternalResource.supports(request)) { return stubbedExternalResource.handle(request); } } throw new RuntimeException(String.format("External resource '%s' is not stubbed.", request.getUrl())); } } catch (URISyntaxException e) { throw new RuntimeException(e); } } }; client.setPrintContentOnFailingStatusCode(true); client.setThrowExceptionOnFailingStatusCode(true); return client; } }
What I've got above is an InternalRequestDispatcher that understands difference between internal request and external request. It also wraps around the application so that it can dispatch internal request to. ResponseHandler is responsible for conversion between HtmlUnit response and the application response.