Constructor injection, and how it simplifies unit test setup
I’ve recently been reading Growing Object-Oriented Software Guided by Tests (GOOS), and one (of the many) aha moments was a piece of test code that mocked the collaborators and instantiated the object under test – all in the declaration of the test’s private fields. I am particularly fond of this approach for two reasons:
- The test code setup is minimal and easily scanned
- This approach encourages all required collaborators to be passed in through the constructor (aka constructor injection)
I’ve included an illustrative example below using Mockito, the actual test isn’t important but it proves this setup style works.
import org.junit.Test;
public class ItemCheckerTest {
private final ItemFetcher itemFetcher = mock(ItemFetcher.class);
private final Notifier notifier = mock(Notifier.class);
private final ItemChecker itemChecker = new ItemChecker(itemFetcher, notifier);
@Test
public void notifiesStoreManager() throws Exception {
given(itemFetcher.fetch()).willReturn(new FetchedItem());
itemChecker.check();
verify(notifier).notifyStoreManager();
}
...
}
For those unfamiliar with Mockito, the given call stubs a query, while the verify call uses a test spy to check a command call was made.
The important lines are the 3 private member variables of the test class, the first 2 use Mockito’s mock method to instantiate test doubles for our collaborators. The 3rd member variable (itemChecker) is the object under test, you will notice that it is instantiated with both of its required collaborators in the constructor. These 3 lines perform all the wiring we require for our test, without having to resort to @Before methods to set properties.
The reason we can leverage the member variables for this setup is that JUnit creates a new instance of ItemCheckerTest for each of the test methods (@Test). Providing each test with its own set of collaborators ensuring each test runs in isolation.
The most important side effect of setting up the test code in this fashion is that it promotes the use of constructors for wiring up collaborators. Using the constructor for collaborators has a couple of very appealing aspects:
- It becomes impossible to create circular dependencies between your objects
- Your objects are less prone to wiring bugs as they are upfront about their required collaborators.
Why would you want to be upfront about your collaborators, Steve Freeman & Nat Price (GOOS) have this to say:
Partially creating an object and then finishing it off by setting properties is brittle because the programmer has to remember to set all the dependencies. When the object changes to add new dependencies, the existing client code will still compile even though it no longer constructs a valid instance. At best this will cause a NullPointerException, at worst it will fail misleadingly.
Miško Hevery also has a great blog post on constructor vs setter injection.
12 Comments to Constructor injection, and how it simplifies unit test setup
“JUnit creates a new instance of ItemCheckerTest for each of the test methods @Test” – Interesting, I didn’t know that was the case. I thought it didn’t do that, hence always using @Before on a setUp method to create a new ‘itemChecker’ for each test case.
I’ve always been an advocate of constructor injection over setter too.
Yeah, I always used to rely on @Before as well
http://martinfowler.com/bliki/JunitNewInstance.html
An example in Groovy with Spock:
http://meetspock.appspot.com/?id=33001
July 12, 2011
I guess it is better to use @InjectMocks annotation. Don’t code for testing ;)
See – http://docs.mockito.googlecode.com/hg/org/mockito/InjectMocks.html
Hi Faith,
One of the key points of my post is how favourable constructor injection is over setter injection.
Using @InjectMocks (which uses setters), while saving lines in the test set up, forces you to use setter injection, allowing objects to be partially initialised when constructed (which is what we are trying to avoid).
As far as keystrokes are concerned I feel
private ItemFetcher itemFetcher = mock(ItemFetcher.class); private Notifier notifier = mock(Notifier.class); private ItemChecker itemChecker = new ItemChecker(itemFetcher, notifier);
is fewer lines, and simpler to understand and use than the @InjectMocks approach
@RunWith(MockitoJunitRunner.class) ... @Mock private ItemFetcher itemFetcher; @Mock private Notifier notifier; @InjectMocks private ItemChecker itemChecker;
The docs say: “Currently it only supports setter injection. If you prefer constructor injection – please contribute a patch.” However if you use constructor injection as shown in this post then there is no need for extra annotation magic.
July 12, 2011
Hi Richard,
I thought you needed to inject dependencies from unit-test and that’s why you used Constructor Injection.
I prefer to use annotation based configuration because of production code implementation difference.
I favor to use @Autowired in properties that makes code more readable I guess. Anyone can understand the dependency will be managed by container in one look. No need to check for setter or Constuctor.
Another thing is about change on dependencies. If I add a new dependency to ItemChecker, there is no need to modify Constructor.
@Autowired ItemFetcher itemFetcher; @Autowired Notifier notifier;
vs
ItemFetcher itemFetcher;
Notifier notifier;
@Autowired
public ItemChecker(ItemFetcher itemFetcher, Notifier notifier){
this.itemFetcher = itemFetcher;
this.notifier = notifier;
}
Just to clarify, in the example outlined, the constructor is the only way to instantiate the ItemChecker – both in production code (via the IoC container) and in the test code.
I guess it comes down to how you view a constructor, personally I prefer the 2nd option with @Autowired on the constructor as it makes the class upfront about what collaborators it depends on when it is constructed instead of having to look at the IoC container specific annotations on its private members.
The constructor approach can also be used across all types of objects, whether they are managed by an IoC container or not.
So positives for constructor injection:
+ Avoid cyclic dependencies
+ Upfront about dependencies (avoid wiring bugs that occur at runtime)
+ Immutability of ItemChecker to ensure we don’t mess with its collaborators at runtime
+ Works with IoC and non-IoC code
Negatives:
- Slightly more code for a collaborator (although if setters are needed for InjectMocks then I would say you end up with less code having a single constructor vs a setter for each collaborator) [actually a positive?]
Discussion also on http://groups.google.com/group/mockito/browse_thread/thread/487f2758c1bbb9c4
July 28, 2011
[...] http://www.rapaul.com/2011/07/10/constructor-injection-unit-tests/ Eco World Content From Across The Internet. Featured on EcoPressed Cloud computing could lead to billions in energy savings [...]
Not sure about constructor injection, there are pros and cons. The article mentions the pros but doesn’t mention the situation isn’t as clear cut:
For example, constructors are less semantically meaningful: it’s difficult to identify which objects map to which constructor parameters (e.g. does the Validator go in constructor parameter 2 or 4, I never remember).
Also, the more services an object needs the longer and more unwieldy the constructor call becomes.
Hi Ricardo,
You are right, my post was a little one-sided :)
The fact that setters include the name of the property does make them easy to read. But I would say with tooling support in IDEs this isn’t a problem when writing the code. And when reading the code the variable name for the arguments makes them self explanatory. e.g. new ItemChecker(itemFetcher, notifier)
I also think that an object that has more than 3 or 4 collaborators is a smell, being confused over the ordering of 8 constructor arguments should be guiding us to split the class into smaller more cohesive classes.
I guess what I’m trying to say is, there are very few situations where I feel a setter is preferable :)
Hi Richard
Don’t get me wrong, I agree there are a lot of benefits to constructor injection.
I will note that even just 3-4 constructor arguments can look ugly, especially if you need to annotate them with named qualifications, etc.
I think Fowler probably said it better than I could:
http://martinfowler.com/articles/injection.html#ConstructorVersusSetterInjection
Of course, the most important benefit of setter injection is that its the most widely used and therefore easiest to grok convention. Maybe something of a Betamax vs VHS thing.
Leave a comment
Subscribe
Recent Posts
Tags
- Plugging your smart phone into a screen has got to be the future http://t.co/1EVJ9oUx 12 hrs ago
- What's the low down on broadband in Auckland? Don't need a homephone, 60GB plan. Any recommendations? 12 hrs ago
- Huzzah for git-svn 6 days ago
- More updates...
July 10, 2011