dependency Injections into Servlets (For Mocking)
Brought to you by:
russgold
I've been using HttpUnit for a while to unit test HttpServlets.
Now, I'm trying to mock a class that the servlet is using. Currently, it's very awkward and the code is hard to read (invoking with dummy request to get the invocation-context and access the created servlet).
I'd like to be ebale to inject a mock dependency to a servlet when run from HttpUnit's ServletRunner.
Thank you!
Can you explain the problem? Maybe a code sample?
I'm writing a servlet (in this example HelloWorldServlet) which sole purpose is to "handle network related logics" and then use some "BusinessLogicsService" to serve the business logics.
Here is example code:
HelloWorldServlet.java
BusinessLogicsService.java
When instantiating the test, it looks like this:
The servlet container creates an instance of HelloWorldServlet using the NoArgsConstructor.
Which means, I can not access the servlet directly and inject my mock dependency.
My purpose now is to write a UNIT test for 'HelloWorldServlet'.
I want to be able to test the servlet only by injecting a Mock SomeService instance from the tests (for example a mock created by Mockito framework).
A solution I found was invoking a Dummy request, catching the InvocationContext, getting the servlet and changing it in runtime. This way is messy and not ellegant.
Can you offer a better way to inject such dependency?
Sure. I do things like this all the time, using the SimpleStub framework (http://simplestub.meterware.com)
First, create a factory class for your business service, using an interface:
interface BusinessLogicsServiceFactory {
BusinessLogicsService createBusinessLogicsService();
}
and use it in your servlet like this:
:
private BusinessLogicsService businessLogicsService;
private static BusinessLogicsServiceFactory factory = new BusinessLogicsServiceFactory() {
BusinessLogicsService createBusinessLogicsService() {
return new BusinessLogicsService();
}
}
But now, in your unit test setup (before the servlet is initiialized), you can do this:
private Memento memento;
@Before
public void setUp() throws Exception {
memento = StaticStubSupport.install(HelloWorldServlet.class, "factory", new TestFactory());
}
@After
public void tearDown() {
memento.revert();
}
Now when the test is run, it will use the test version of the factory, which creates a fresh copy of the test version of the business logic. The tearDown puts back the original version (because it is good practice for unit tests to clean up after themselves).
You may, BTW, find SimpleStub a much easier way of creating test doubles than mocks, as you can use normal Java code to do explictly what you want, rather than a complex series of library calls.