Does anyone have experience writing UnitTests for servlets? The problem we are running into is that setting up the environment to run a servlet is extremely complicated.
Course of the discussion has nothing to do with Servlet testing, but it is about web applications testing. IMO: 99% web applications do not need custom Servlets at all! MVC2 paradigm (look at Struts http://jakarta.apache.org/struts as an implementation) eliminates need for them and simplifies Java web development enormously (testing too). Good testing tools are HttpUnit and Cactus (http://jakarta.apache.org/cactus/)
I've done some, with an adapter I wrote that lets you create the request object, hand it to the servlet, then interrogate the response object. It's available at http://www.iac.net/~crawford/programming/testharness.zip.
Actually, I have done some work adapting JavaUnit to work with Servlets. I didn't take the approach you did though - I wrote a subclass of TestCase that contains utility methods to invoke a servlet URL with a GET or POST request and pass HTTP parameters to the request. I then get back the result from running the servlet (the HTTP) and then parse it to determine if the test passed or failed.
This way you don't have to mess with setting up the servlet environment specially.
-- KyleBrown
Kyle, can you post your JUnit extension mentioned above?
The problem with this approach, though, is the same one I encountered with some of my first CGI scripts: failures that generate incorrect output are easy to spot, but more serious errors are opaque. JUnit's nice exception traces won't do you any good. -- GlennVanderburg
To test ActiveServerPages I have ended pushing as much of the application out of the ASP and behind a facade. I can then UnitTest the facade. We combine this with non-automated testing (people with a check list in front of a browser). -- FabianLeGayBrereton
I try to just have interface code (HTML) in the ASP. The ASP interacts with the model through the facade (a COM/MTS component). MartinFowler discusses this in an article on ApplicationFacades.
Apart from allowing the application to be more easily tested this also overcome problems with ASPs crappy exception handling and debugging.
-- Fabian.
An Excellent approach. I do this too with Servlets and JavaServerPages. If you think of your Servlets and JSP's as being the "view" and "controller" layers in an MVC architecture, you should be able to test the "model" layer separately.
-- KyleBrown
There are servlet frameworks that encourage this approach, too, such as webmacro[1] and possibly enhydra[2] (although I haven't really looked at the latter).
My favourite framework for this is freemarker. http://freemarker.sourceforge.net/
Our experience reinforces that of Kyle - the more you test in the model the better. We almost view our Servlet testing as being on par with functional tests in that we run them less often (only several times a day vs. hourly). The real tests are run at the unit level on model classes.
We used to do a lot of opening a socket to a servlet and comparing expected output with actual output - but we have backed of this a bit as its slow, very fragile to changes unless you repeat much of the code you were using to generate the output in the first place. We are starting to move more down the road of creating a result model - which we can query and verify in unit tests. You then test that each result piece can render itself out into html (probably by some painter object - but often the simplest thing is to start with toString to get it going).
Finally you can get a lot of mileage from stuffing a HashTable into an HttpRequest with known key,value pairs and testing that some Factory like object extracts the values and creates the objects you want (or stuffs them back into an existing object). This way you can test more without having real servlets and having to rely on post and get routines. This object can also do your validation and answer your error messages which your servlet can then send back. Using this approach means that your servlet starts looking skinnier and skinnier (unlike many of the articles you see in magazines) -- TimMackinnon
I too have been looking at ways of testing servlets and JSPs. My current approach is what has been suggested above - separate the model from the view (JSP) which allows you to write your UnitTest code for the model.
However, I would still like to test the JSPs. My feeling is that there are several things that need to be tested which would be helped a great deal by ensuring that the documents generated from the JSP are well-formed XML. You can then use a parser to validate the document and find expected elements.
As a result of this I too am tinkering with extensions to JUnit which enable easy testing of JSP output.
Has anyone tried this approach ? Or am I barking mad? :-) -- ChanningWalton
There seems to be a fair amount of interest in unit testing servlets, what do people feel are important features for unit testing servlets? Here are some of my ideas off the top of my head:
Though perhaps not strictly a servlet test, a way of testing a system of servlets with bombardment of concurrent requests would be useful (so useful I'm sure it's been done before, but I can't remember seeing it anywhere). -- DannyAyers
I've implemented a rudimentary extension to JUnit 3.2, junit.servlet.TestRunner so that you can have the request and response objects available in your TestCase objects (for those objects that just have to have the complete context before you can test them). Right now it is written for SilverStream, I'll be making a PlainJane? Servlet version in the next few days. -- PeteMcBreen
Details are on EnhancingJunit page, code is at http://www.mcbreen.ab.ca/pete/TestRunner.java -- PeteMcBreen
Yet another framework for testing servlets can be found at http://www.egroups.com/files/extremeprogramming/servlettesting.zip. It provides dummy implementations for most classes in javax.servlet.http and extends them with setters and getters for testing. -- JohannesLink
I believe testing should also happen end-to-end. For our Web application framework we also created the necessary infrastructure to do performance and functional testing, where functional testing is embedded in our automated daily build and (unit) testing process. However, our stuff is C++ based and not Java. -- PeterSommerlad
I downloaded the TestRunner PeteMcBreen posted and ran it. He did a great job. I needed to be able to access the HttpServletRequest and the HttpServletResponse, so I modified JavaUnit to allow me to pass them to the TestCase. I also pass the PrintWriter to TestCase, that way I can output text to the browser instead of System.out.println. The problem I have is passing values through the request. I was trying to find a way to change the request. The only way I can get them there is from a page... However, JavaUnit and running Tomcat in a debugger work very well. If anyone wants the changes to JavaUnit, send me and e-mail. I did this once before for AtgDynamo. I think JavaUnit needs a mechanism to pass parameters to TestCase. -- MarkStang
JavaCon? 2000 Presentation - Servlet Unit Testing: http://www.delphis.com/javacon2000/servlet.html
J2EEUnit has been renamed Cactus and absorbed into Apache's Jakarta project. It is now at http://jakarta.apache.org/cactus/. Also interesting is the mockobjects project at http://www.mockobjects.com, which provides mock versions of the HTTP servlet request, response, and session objects, as well as many others. -- WilliamPietri
HttpUnit at http://httpunit.sourceforge.net. -- GarethCronin