I want to write a unit test for a servlet class that makes a call to a web service through java.net.URL.
I can create mock request and response objects to send to the servlet's doGet method easily (using the techniques from the pragmatic programmer text on junit), i.e., creating MockHttpServletRequest, MockHttpServletResponse, and passing these to doGet.
The part I'm having trouble with is the URL open in the servlet.
Right now, i'm just choosing between a call to a function that opens the URL and returns a string (the production code) and a call to a function that returns that directly returns a string for a fixed URL (the test code)
Ideally i'd like to have a doGet method in which the testing code is invisible - the choice between the function that makes the network access, and the one that directly returns a string should be transparent to doGet.
i can think of a number of ways of achieving this, but none feel right.
Example 1: wrap the function in a class that has a testOn boolean, and a setTestMode method; junit init can set the testMode to true, default is false. the testOn decides which method to call. negative is that i need a new class, seems like it could get out of hand.
Example 2: have two classes implementing the network access, one of which is the mock; have junit reload the mock class, production code load the regular class (or somehow remap the production class to the mock class). negative: not sure how this would be done; seems clumsy.
Example 3: have a class with static fields indicating if i want to use mocks, and condition the URL access in the servlet based on the field values. negative: feels like global variables.
Example 4: extend URL, so that the production code will work fine if i switch to URL only (but java.net.URL is final).
I couldn't find quite the right answer through a morning of searches, hence my turning to the collective wisdom of SO.
Thanks, Adnan
ps - I should mention that I don't have to use java.net.URL, anything that's equivalent will work.
Your second option is the "right" option. The call to the external URL should be encapsulated in a service. The service, then, is injected into the servlet that uses it. This is one place where Inversion of Control comes in handy.
In your unit test you'd inject the test implementation, in real life you'd inject a real implementation. It can be as simple as providing a setter for the service and defaulting the implementation to the "real" one.
This kind of thing is a canonical example for IoC/DI.
Looks like you are reinventing the wheel - and you invented it yet again in Example 2. This is typically implemented using dependency injection and is actually the best solution software developers came up with so far.
Hide your web service call behind an interface. One implementation does the actual call while the other is a mock that you can configure. If you are not using any DI framework (Spring, Guice, EJB/CDI), replace production implementation with mock manually in the test.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With