Constructor injection – Why I no longer use autowired
This post focuses on Java and using something like Spring or CDI for dependency injection. If you aren’t using Java this post can maybe still apply to you, constructor injection can and should be implemented in many languages. If you’re confused about autowiring, check out some details here.
I have always used autowired and annotated my fields with autowired only because I had gotten used to it. One of the earlier code bases I worked on in Java performed all dependency injection this way. Relying on the Spring DI container and the @autowired annotation was a way of life.
If you know where I’m going with this post you may have guessed, that code base had very few unit tests and testing in general. It can be painful to test when you’re using a lot of autowired fields. You need to create mocks with stubs and make sure they’re injected with your mock DI container. This ends up requiring more overhead and more headaches trying to get testing to work. I was often banging my head against the wall trying to get some decent tests made with autowired until I ran across a post on reddit.
Along with just making testing harder, I felt like I was constantly struggling with getting SpringJunit runner types of classes working. I think I went through 3-4 different Spring/Junit/testing libraries before I found one that consistently worked. Not pictured above is the xml/Java needed for mocking.
In other languages I have often relied on injecting dependencies with the class constructor. Java and autowired kinda lulled me into this laziness which I just couldn’t stop. I’ve been switching all my code to constructor based injection mainly because of the ease in testing. My tests no longer need to initialize a mock DI container, or inject mock objects with it. My tests have gotten much simpler and I no longer worry too much about the hassles of getting all the different junit/mockito/jmock/etc working together with a mock DI container. I was using xml for some of my mock DI containers and I’m definitely thankful that I’m no longer doing that.
One big benefit I found not mentioned in the article linked above, I feel like this helped me find some code smells I didn’t notice when I was using autowired. I tightened a few things up when I noticed my constructors were getting out of control. I noticed I started following better patterns of composition once I started using constructor injection. I didn’t realize how many classes I had where I was autowiring way too many dependencies.
I’m not going to lie, after switching a few projects from autowired to constructor injection I got a huge uptick in unit tests and coverage. More time coding, less time fighting with Junit/Spring, tests became way easier to write.