At my Guice presentation recently, I used some small code exercises to demonstrate the basics of Guice. Here is my simplest example, involving a Service, a Client needing a Service injected, a test case, and an Application.
First, the Service:
Next, the Client, and it’s test (JUnit 4):
And finally, an Application that ties it all together using Guice:
During the talk, Jeff Grigg had a question followed by an interesting comment. For his question, he asked me to remove the @Inject attribute from Client and re-run the test. I did, thinking I was about to demonstrate a typical helpful Guice Exception. But the test passed. I was momentarily lost, until I remembered that the unit test did not use Guice at all. I ran the Application just as a sanity check, and it was indeed broken.
Jeff was on it like a hobo on a ham sandwich - I had broken the application but the test still passed. My test did not justify the use of the @Inject attribute.
He was absolutely right. I realize now that I had been following the example from the Guice Developer Day Slides, which had taken a non-Guice example and migrated it to Guice, leaving the JUnit test unmodified so that, like my test above, it continued to manually pass a mock to the client code and did not use Guice. This, I realize now, is fine for a tutorial but it not truly Test Driven Development, where every line of code has some test to justify it’s existence.
Naturally, Jeff raised the question - should Guice then be used in unit tests?
I think the answer is yes, why not? After all, Guice suggests it be thought of as the new new, and that using Guice is no more work than plain old factories.
If Guice were used in unit tests, then the tests would naturally require that the code have the necessary @Inject attributes, or whatever other attributes are necessary for Guice. The only difference would be that different Modules would have to be created for the tests, which contained bindings which differed slightly from the production Module(s).
I tried implementing a new client, strictly adhering to TDD and using Guice in my unit tests. Here is what I came up with.
There are two things I notice. One is that my mission is accomplished - my Client’s @Inject attribute is now truly unit tested - the test will fail without it. As a bonus, Client is slightly simplified in that it no longer needs a constructor which accepts a Service. The other thing I notice is that the test is somewhat more complicated, but really it’s only the addition of a Module and Injector.
My feeling is that it’s worth the extra effort to use Guice in unit tests, if you’re going to embrace Guice in your production code anyway.
In a future post, I’d like to investigate whether there is a better way to integrate Guice with JUnit, alleviating the need to write boilerplate unit testing Modules over and over again. Just tonight I noticed both GuiceBerry and AtUnit which potentially address this and look somewhat promising.