This post originated from an RSS feed registered with Java Buzz
by Geoffrey Wiseman.
Original Post: Configuring Dependency-Injected Unit Tests in Spring
Feed Title: Furious Purpose
Feed URL: http://www.jroller.com/diathesis/feed/entries/rss
Feed Description: Thoughts and experiences on technology and software.
I've had the opportunity to spend a lot more time with Spring lately, using Dependency Injection
on a pretty regular basis. I've also had some time to explore the ins and outs of using
Dependency Injection with unit tests.
Let's start with the basics: Don't.
Don't Inject Unit Tests
If you don't need to inject your unit tests, then, to be honest, I wouldn't. You've got to go
to the trouble of setting it up and potentially varying it on a test by test basis. In many
cases, you'd be better assembling the unit you wish to test by hand using the constructor
or setters in the unit test itself. This is the pattern shown on
this PicoContainer page, showing the
substitution of a dependency with a mock.
This is, of course, an over simplification. There are times when it's useful, or at least,
convenient, to inject a unit test.
When to Inject a Unit Test
Ok, so when should you, or might you, inject a unit test?
When a unit requires a lot of dependencies.
If there are a lot of dependencies, it
may be painful to assemble the object with its dependencies or with mocks. If you have
lots of dependencies to a single unit, it's worth asking yourself if this is a design
smell, but if you've already done that, you might consider moving on to injecting your
unit test.
When the test is an integration test.
If you're writing an integration test, you might well want to test the class exactly as
the container would deliver it to a higher-level component, or as close to that as possible.
If you're testing, in part, the IoC container configuration, then it may be useful to
inject the unit test.
There may be other situations: these are the only ones I've encountered. Remind me to
post another blog entry about injecting Hibernate domain classes, while I'm at it.
How to Inject a Unit Test
This part isn't new, so I won't repeat it myself. There are
examplesout there already.
In essence, even if JUnit is controlling the creation of the unit test, nothing prevents you from doing
some reflection against the application context and your unit test to connect the dots.
How to Configure an Injected Test
We've been injecting a few unit tests for some time now, but one of the things that has irked me is
the lack of simplicity around making small alterations to a single dependency, potentially deep in
the dependency chain of a high-level service that I might be testing.
A reasonable solution recently came to me: using Spring's
Bean
Factory PostProcessors, and in particular, the PropertyOverrideConfigurer, there is a reasonable
solution. I can include a single post-processor, even on a test-by-test basis, that overrides the
few properties that need to be overridden.
Imagine, for instance, that I had a service that invokes upon a controller that delegates to a strategy class. If I
wanted to test that service, I might want to alter a property of that strategy class. In order to do that, I might
prefer not to be forced into constructing the service, all its dependencies, and all of its dependencies all the way
down the chain.
Using a property override configurer, I can do just that:
strategy.threshold=5
Now all I have to do is parameterize my injected unit test base to allow me to specify an additional spring configuration
file to add to the application context on a test by test basis, and the problem's solved.
This strategy only goes so deep; Spring's override configurer is less-well-suited for more complicated changes, like
changing a single property on a map, or altering dependency chains. If it has those capabilities, I haven't yet
figured out how to make use of them. Still, it's a start. Perhaps if I wrote my own post-processor...