I'm in the process of writing unit tests for my struts based web app. I think I'm going to use a combination of strutsUT, httpunit and mocks. The methods (insert, delete etc) in my DAO's are all static and obtain a connection to the database from a static method in another class. I'm wondering if the use of static methods will affect the usefulness of mocks, or unit testing in general?
Your best bet from my experience is to avoid the static methods. The reason you want to do this is because in order to best facilitate unit testing, you want to program to interfaces as much as possible in order to decouple yourself from dependencies as much as possible. Since you are progbramming to interfaces, and you can't define interface methods as static, you cannot enforce a rule that implementations of your interface methods are static.
Programming to interfaces tremendously enhances unit testing by allowing you to inject your implementation dependancies at runtime, meaning you can easily provide mock implementations of dependencies in your object under test. You can do this using inheritance as well, as opposed to strictly using interfaces, but in general programming to the interface should be preferred.
Let me give you a real world example. The architecture calls for using service classes (they might be business delegates acting as session facades to EJBs, or they might just be POJOs) in the business layer to access the DAOs. The Struts Action classes call the service classes. I use a ServiceFactory to create instances of my service classes. At runtime, I have the application load an implementation of the ServiceFactory interface which creates the specific implementations of the service classes that the app needs. We also have a DAOFactory interface which the service classes use to get instances of the DAOs (which are programmed to interfaces). The two factory classes are obtained from a ServiceLocator, which can itself be configured to supply varying implementations of our interfaces.
I use the template method pattern to provide a base Action class to handle the retrieval of the ServiceFactory from the ServiceLocator, and then pass it to an abstract method which requires the standard Action arguments in addition to a ServiceFactory argument. This makes it dead simple for me to unit test my Struts Actions using EasyMock as painlessly as possible. I also do something similar for DispatchActions, although that's technically not the Template Method Pattern.
Here are some of the specifics...
I'll only put one method into this particular service class, just for illustration.
You should now be able to get an idea how simple it will be to test the behavior of my Action class, BrowseCatalogByProductsAction, using only mock objects (I use EasyMock). My Action does not depend on any specific implementations of either ServiceFactory or CatalogServices.
My unit test for this action will call the five argument execute() method of BrowseCatalogByProductsAction directly. I've previously unit tested the BaseAction to show that it will call my five argument method in classes that extend BaseAction, so I don't need to call the four argument standard execute() method in the subclass. This allows me to have my test provide a mock implementation of ServiceFactory, whose createCatalogServices() method I will have return a mock implementation of CatalogServices, which in turn I will set up to have its findProductsList() method return just some arbitraty List. Using EasyMock makes this whole process really easy.
This idea of injecting your dependancies at runtime can permeate your architecture, making every component easy to test. Where a component is tougher to test, such as if you are using SessionBeans, then factor out the business logic in the SessionBean method into another class which can be easily tested. Here's an example of that, where in this case CatalogServices is actually a SessionBean instead of a POJO:
You will see that in this case we have the general plumbing code and the transactional demarcation inside the method, but the actual business logic is delegated to the FindProductsListLogic class. You'll notice that the FindPRoductsListLogic has its dependancy on an implementation of CatalogDAOFactory injected via the constructor. Since CatalogDAOFactory is an interface, and CatalogDAO is an interface, we can have a mock implementaiton of CatalogDAOFactory which creates mock implementations of CatalogDAO, making it quite easy for us to unit test the Logic class. Here's more code illustrating this. Naturally the CatalogDAO class would have more methods than the one which I'm using for illustration.
Hope this answers your questions and maybe gives you some ideas.
posted 13 years ago
Here's a unit test for the Struts Action in my previous example.
[ July 11, 2005: Message edited by: Jason Menard ]
posted 13 years ago
I just noticed the original post was made way back on June 24th. Hate it when that happens. Oh well.