Sometime back, using the Spring Framework and jUnit 4.x was not very elegant. Spring only supported dependency injection by sub-classing their AbstractDependencyInjectionSpringContextTests class. The coolest thing about jUnit 4.x was the implementation of annotations and the elimination of the requirement to extend the jUnit TestCase class. Obviously, this was considered an issue by many people, as several projects created their own solutions for jUnit 4.x integration. One such implemenation was Unitils, which I used on several projects. I did not take advantage of all of the Unitils features (Mock Objects, JPA, or DBUnit integration), only the dependency injection and a little of the Hibernate and Transaction management support.
Someone recently hipped me to the fact, that somewhere along the way, Spring finally added support for jUnit 4.x. I wanted to see if I could possibly eliminate the need to Unitils. Only have only played with the integration for short time, but it appears to do what is required. The only real issue I encountered was having to downgrade from jUnit 4.5 to jUnit 4.4. Unfortunately jUnit 4.5 broke the integration, and will not work. However, moving back to jUnit 4.4 solved all of the issues.
The basic class level annotations that you need to be aware of are @RunWith(SpringJUnit4ClassRunner.class) and @ContextConfiguration(locations = { “/com/sample/resources/applicationContext.xml” }). I have seen the @RunWith annotation used by many new jUnit extensions, it seems pretty cool. The ContextConfiguration is pretty obvious, you can provide a list of XML files which contain your Spring context
Next you can simple provide the @Autowired or @Resource annotation to your test class properties. Spring will then inject those objects for you at execution time. They did provide the @Qualifier(“alternateBeanName”) annotation which allows you to remove possible ambiguity.
One thing that was not entirely obvious to me was the @TestExecutionListeners annotation. One of the Spring examples had it set to {}, which effectively turns off the dependency injection. It would have best to leave it out! Anyway, there are several other Listeners that you might want to be aware of, such as dealing with Transactions and a dirty spring context.
On of the more interesting annotations, (which was not in Unitils) was the idea of making tests specific to an environment. While this is probably not that common, I have had situations where I can only run a test in the CI (Continuous Integration) environment, or maybe only I only want it to run on my development box. The @IfProfileValue annotaion provides this ability. The default implementation allows you to do simple “if logic” base on Java properties. It is also possible to define your own configuration (something that determines the value of the requested attributes) class, using the @ProfileValueSourceConfiguration(Include.class). Pretty cool, I can actually see using this feature in the future.
There are plenty of other annotations that will be useful, such as @BeforeTransaction, @AfterTransaction, @Rollback, and @NotTransactional.
I believe that the @RunWith and @ProfileValueSourceConfiguration annotations can be very useful in building a consistency unit test strategy, effectively hiding much of the noise associated with most jUnits (noise = configuration and setup tasks). Personally, I find jUnit 4.x much more elegant that the original (pre 4.x) strategy, providing a much cleaner implementation.
I believe that unit testing is essential to projects, and will continue on my personal mission to push for Test Driven Development. I truly believe that done right, “Testing is basically Free”… especially when you consider the integration environments provided by Spring and development tools such as Eclipse. How can anyone afford NOT to test? Enough soapbox for the day, here was yet another little TDD article.