I came across this question on the
testdrivendevelopment Yahoo! group.
I’d like some advice/opinions on how to test some existing code. It’s a web application using Spring and struts.
I have a class called the ProcessedFilesManager which contains a number of methods used by Struts Action classes. This manager communicates with five different DAOs to get the information that some of the Struts actions are interested in. Now, I want to test this manager class (ProcessedFilesManager). The way I’ve started doing it is stubbing up each of the five DAOs, however, this is proving to be quite painful. I didn’t want to use a mocking approach, nor did I want to use a DB solution like Hypersonic, but now I’m open to suggestions.
Seeing as there a number of approaches I could use, what do you think would be best for this situation?
It feels wrong to stub the DAOs because what if I’m introducing behaviour in there that differs from the actual DAOs? My tests will not be accurate.
Any advice/comments would be much appreciated.
I used to have this fear, and I do something now that has eliminated that fear.
When I stub a DAO method, I make an assumption about what that DAO method does. I used to be worried about making the wrong assumption, but now I have a contract test for the DAO interface that tests for the assumption I’m making in my Service test. The contract test gives me confidence that any implementation of the DAO method passes the same tests, so every implementation of that DAO method behaves in ways that the clients rely on. Once I have this, I feel comfortable stubbing that DAO method that way in a Service test.
A contract test describes the behavior of an interface. I describe contract tests in some detail in JUnit Recipes, recipe 2.6, although back then I called them “abstract test cases” because I hadn’t yet discovered the better name “contract test”. If you prefer, I’ve provided a diagram showing some contract tests for a typical DAO class.
Since classes inherit methods from their superclasses, the
Hibernate Customer DAO Testwill inherit the contract tests from its superclass, as will the
JDBC Customer DAO Test. This means that each implementation has to pass not only its own tests (like
testClosesResultSet()) but also the tests inherited from
Customer DAO Contract Test Template. (I call it a “template” because it plays the role of template in the Template Method design pattern.) When you test-drive a new implementation of
Customer DAO, simply make the new test extend the contract test template and you’ll automatically inherit its contract tests. This way, I have confidence that any implementation of
Customer DAObehaves the way I’d expect any
Customer DAOto behave. Returning to our example, these contract tests give me confidence to stub the DAO when I test-drive the Service, and that confidence brings with it a happy side effect. I am confident that
findAllWithPendingOrders()only returns customers with pending orders, so I don’t have to worry about that issue at all when I design the Service that reports all customers with pending orders. Now that I notice it,
Report All Customers With Pending Orders Serviceis really just a
Report on Customers Servicethat needs a
Customer Filter, which could be a
Pending Orders Customer Filter. I don’t think I would have felt comfortable with this level of generalization if I weren’t so confident in the way I’ve separated the responsibilities.
The next time you want to avoid stubbing a method because you’re worried you’ll make a wrong assumption about what the method does, try writing enough contract tests to give you the confidence you need. I think you’ll like the results.