I'd like to share my experiences about unit testing (using JUnit) Java servlets outside of the servlet container. Agile world tells us that we should automate as much tests as we can - it would be good if all aspects of the developed system are completely tested. We should test functional as well as non-functional requirements of our systems. But can all tests be automated? What is the REAL value of such tests? The reality brings us problems and pitfalls even experienced developers fall into. I will present such story regarding automated and manual testing of Java servlets.
The problem
Quite recently I had do develop some "proxy" servlets facilitating Ajax request from web browser to our middleware layer. We couldn't directly send Ajax requests because JavaScript security model doesn't allow to request data from other address than it was originally downloaded (similar restriction to Java Applet).
All right then, our servlets were not doing any amazing job (some input and output transformations were needed, however) but I made some bugs even having 100% test code coverage (used Cobertura 1.9).
What about automated tests?
Well some things can be automated, some not. Let's start with unit testing servlets. The simplest (containerless) solution to unit test servlets is to use EasyMock in order to provide mocks for HttpServletRequest, HttpServletResponse, etc. Yes, I know you can use Jakarta Cactus but I did it quicker using easy mock :)
OK - I unit tested my servlets and was very happy that I saw the green light. I started the sevlet container accessed the web page and it seemed to be working. Unfortunately I didn't see that the servlet set some instance variables after the first invocation and these variables couldn't be changed afterwards. The effect was disastrous - servlet was sending the same request all the times not taking into account passed parameters. We could have checked this problem by invoking my doXXX method multiple times with different parameters - we didn't.
Did we test our servlets manually?
Yes, non-automated tests were performed using JMeter. I used JMeter to check how our servlets behave under heavy load. The performance and load results were OK but I noticed in the logs many entries similar to this one:
Checkout date [2008-10-15] is earlier than or equals checkin date [2008-10-11]
Well the log message lies! And the implementation is well-coded (really). What's wrong?
This is how I discovered problem with SimpleDateFormat - not to mention the help from FindBugs that showed me big red light in the affected lines :)
What was wrong?
java.text.SimpleDateFormat has synchronization problems and cannot be used as a static class fieldLesson learned
When you want to test your servlets:
SimpleDateFormat) - either using Eclipse/NetBeans plugin or Maven reportUsing load testing tools you can discover quite interesting and unexpected problems - without such test you cannot be sure your application will work under every circumstances.
After implementing all fixes our servlets seem to work very well even under heavy load. We don't have any thread-safety issues and our dates are parsed correctly ;)
Conclusion
To conclude shortly I will say that testing servlets is not easy. You can write unit test, "inject" mock request, response, etc. objects but you still will not be sure how your system behaves inside servlet container under heavy load (you should also try using Jakarta Cactus framework).
Agilists say that you should automate as much tests as you can. I generally agree with it but sometimes it makes more sense to perform some manual testing which simply works. I probably would not discover all the issues I revealed using only automated tests.
If you have other experiences with testing Java servlets, please share them here.
Comments
About SimpleDateFormat
June 19, 2008 by Riccardo (not verified), 16 weeks 3 days ago
Comment id: 1593
Nice you pointed to a very subtle issue with SimpleDateFormat :-)
It is strange how 99% of the people I worked with simply skipped the part in the docs where it explicitly says that instances for that class are not threadsafe (or they don't know what thread safety is about).
They usually implement it as a static field in some utility class without any kind of synchronization; when I stumple upon such terrible mistake I usually try to teach the writer about the fact that similar code WILL cause problems and you know what's the answer I get (always the same one!)? "we never had problems with that"!
next time I find myself in that situation I will try to link them this blog entry, hoping they believe at something that's wriitten.
Thanks
About SimpleDateFormat
June 19, 2008 by pbielicki, 16 weeks 3 days ago
Comment id: 1594
Findbugs and similar
June 19, 2008 by Riccardo (not verified), 16 weeks 3 days ago
Comment id: 1595
People I'm talking about almost don't know the existence of findbugs/pmd and such; simply they won't use them because "they give too many errors"!
Findbugs and similar
June 20, 2008 by pbielicki, 16 weeks 2 days ago
Comment id: 1596
OK - that's the real problem. But, if you use some continuous integration framework (Continuum, Bamboo, etc.) with Maven2 or even Ant script you could easily (at least using Maven2) add the plugin that will be automatically doing the check and sending emails in case of errors or even warnings (depending on the threshold you set)
But anyway - changing the way people think and work is the biggest problem and challenge...
There is a trick to use when introducing findbugs and similar
June 23, 2008 by Sergey Pashin (not verified), 16 weeks 5 hours ago
Comment id: 1597
Exactly, that is the one of the most popular reasons. The trick is this: First just let the Continuous Integration system run findbugs, pmd an alike and show the team the trend of defects found by static analysis such as one provided by our Parabuild. Once the team got used to the fact that there is a system that automatically detects defects, you can begin looking at the most dangerous ones and fixing them, one by one. The trend would go down nicely. When all issues are fixed, it is now possible to ask the team members to run static analysis before checking in new changes and to turn on failing build when any of the issues pop up.
Sergey
Post new comment