Showing posts with label Spring. Show all posts
Showing posts with label Spring. Show all posts

Thursday, December 18, 2008

Autowired JUnit Tests with Spring 2.5

Spring 2.5 ships with great support for integration testing through the classes in the org.springframework.test package. These classes allow you to dependency inject your test cases off of your existing Spring configuration, either by using your production Spring configuration file or one you've defined especially for the test case. This post explains how to annotate your JUnit 4 test cases to be autowired, but there's a lot more too the new spring-test.jar and it works with JUnit 3.8 also.

As setup for all the examples, let's assume there is a simple service that can return a String to you. Imaginative, huh?
public class MyService {

private final String name;

public MyService(String name) {
this.name = name;
}

public String getName() {
return name;
}
}
This service is defined in a Spring XML configuration file as:
    <bean id="myService" class="org.sample.MyService" >
<constructor-arg value="simple service" />
</bean>
To have Spring dependency inject our test case, we're going to have to annotate it with a little information. We'll use the standard JUnit @RunWith annotation to tell JUnit to use the Spring TestRunner, the Spring @ContextConfiguration annotation to indicate the TestCase needs injection, and the Spring @Autowired annotation to inject the MyService field by type.
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration
public final class SimpleAutowireTest {

@Autowired
private MyService service;

@Test
public void testServiceName() {
assertEquals("simple service", service.getName());
}
}
There are a variety of ways to have Spring run your test. Besides SpringJUnit4ClassRunner.class there are also abstract TestCase objects you can inherit from, including some that will expose the ApplicationContext to you. By default, the spring configuration file for the test case will be [TestName]-context.xml. You can easily override this to point the test at your production configuration file. Also, the @Autowired annotation autowires the field by type. In the case of conflicts, you can specify the bean name using the @Qualifier annotation. Consider the following Spring configuration where there are two beans of type MyService in a file named applicationContext.xml:
    <bean id="deliveryService" class="org.sample.MyService" >
<constructor-arg value="delivery service" />
</bean>

<bean id="accountingService" class="org.sample.MyService" >
<constructor-arg value="accounting service" />
</bean>
The JUnit test now requires the @Qualifier field annotation and a configuration file location as an @ContextConfiguration parameter:
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(locations = {"applicationContext.xml"})
public final class AdvancedAutowireTest {

@Autowired
@Qualifier("deliveryService")
private MyService service;

@Test
public void testServiceName() {
assertEquals("delivery service", service.getName());
}
}
To note: if you point the test to the production Spring configuration, then you're running integration tests and not unit tests. Integration tests are valuable and necessary, but are not always a wholesale replacement of unit tests. There's still value in isolation testing each of the components with mock dependencies. What I like about using Spring for the integration tests is that it validates the Spring mapping at test time. On my projects, we occasionally have the unit tests all passing but the Spring configuration contains a circular dependency, and we don't find out until the build hits QA. A Spring integration test pushes up error time to the test phase, when a developer can take quick action and long before QA is held up.

As is standard with JUnit, each test method runs within its own instance of the TestCase. However, the Spring TestRunner will only create one ApplicationContext for all the instances of the test method. This means that if you're test method destroys the state of a singleton bean, then downstream tests methods using that bean will fail. The way to work around this is to annotate your method with the @DirtiesContext annotation. This tells the Spring TestRunner to reload the context between test methods. For instance, these tests will pass when annotated, but fail when not:
    @Autowired
private MyConfigurableService service;

@Test
@DirtiesContext
public void testServiceName1() {
assertEquals("configurable service", service.getName());
service.setName("Updating Name");
}

@Test
@DirtiesContext
public void testServiceName2() {
assertEquals("configurable service", service.getName());
service.setName("Updating Name");
}
There's a lot more in spring-test, but this is a good starting point. The transaction annotations look especially promising, including the ability to open and rollback transactions per method. The only reference I know for spring-test is the Javadoc at http://static.springframework.org/spring/docs/2.5.x/api/org/springframework/test/package-summary.html. Those looking for a Spring starter lesson might consult the DZone RefCard.

The dependencies for spring-test are: junit, spring-context, spring-core, spring-beans, spring-tx, and commons-logging. A sample Gradle script for your build is at href="http://svn.assembla.com/svn/SampleCode/spring-test/build.gradle.
All the code for this post (including Gradle build script and IDEA project) is posted at http://svn.assembla.com/svn/SampleCode/spring-test/ and can be downloaded through subversion with the following command:

svn co http://svn.assembla.com/svn/SampleCode/spring-test

Friday, May 30, 2008

Google Guice by Robbie Vanbrabant

The stars aligned this week: I was called into jury duty the same day Google Guice by Robbie Vanbrabant arrived in my mailbox. Awesome timing. This is my review in which I purposely avoid any juice puns (you know, like saying "the guicy details" and such).

The Content
I'm gearing up to deliver a dependency injection brown bag at work, with the intent of helping teams roll out Spring and DI on more of our projects. I wanted to read this book mostly as a comparison to Spring, but to also see how well DI was explained. I've had the Guice user manual and videos bookmarked for months, yet haven't worked up the motivation to look at either. At 180 pages, it was easy to breeze through this book; the writing was conversational (good!) and the font was big and the pages were small so you really feel like you're making progress when reading. Afterwards, I've been able to have several informed conversations about both frameworks, and I feel like I have a good grasp on the differences despite never having used Guice on a project. So if your situation is anything like mine, then I definitely think reading the book will be time well spent.

Dependency injection, and the motivations for it, are covered quickly, so don't expect too much in that department. Martin Fowler's article is still the best reference I can find, despite it starting to age. This book is really about how to use Guice effectively.

It does a good job of attacking the comparison to Spring head on. People are typically worried about the heavy use of annotations in Guice, despite usually complaining about all the Spring XML in the same sentence. Robbie does a good job pointing out that annotations are just metadata and not really a form of tight coupling. Your code will function just fine without Guice (i.e. in the unit test). There's a good comparison to annotations as offering the same coupling as Javadoc. If you mention Guice everywhere in your Javadoc nobody would complain that your code is tightly coupled. And how much different is the metadata of an annotation from the metadata of Javadoc? (This also supports my biggest gripe about writing Javadoc... if you really follow the DRY principle and strive for cohesive, small classes, then there isn't a whole lot you can say in the docs that doesn't drag a bunch of dependencies into the class. My Javadoc tends to be retardedly simple and I haven't found a good way to fix this). Anyway...

The other concern is that Guice doesn't really do anything that Spring doesn't. I thought Robbie made a good case on why Guice is an improvement on several fronts. The type safety of Guice was well explained. Programmatic bean configuration in Spring is pretty type unsafe. Neither constructor arguments nor their types are checked at compile time, while Guice provides this. And the examples clearly show that bringing up a Guice Injector is a lot easier than bringing up a BeanFactory. The term "lightweight" for Guice seems appropriate. As for the lack of XML... this is probably a good thing. I hear horror stories of Spring configuration explosion, but honestly I've never seen it. If your class explodes to several thousand lines you know to refactor, but when your XML explodes to the same length people tend not to do anything about it. Programmers seem to understand refactoring and modularization when it comes to classes but that doesn't carry over to XML. If your configuration is in Java it's probably a lot easier for a team to recognize and reorganize away from bad patterns. This is kinda compelling for me. As for the IDE support of Java configuration over XML configuration... this argument gets trotted out a lot but the Spring support within IDEA is amazing. I've never had an issue finding my bean definition or with refactorings breaking the XML. Maybe Eclipse is different? Maybe it's time to switch? The biggest issue I have with Spring configuration is finding out what the runtime errors really mean and which of my beans has a bad definition (nested exceptions to 10+ levels anyone?). Guice's type safety and claimed improved error messages should both help here.

The nuts and bolts of creating Injector objects are well explained and easy to follow. Robbie makes a good point that Guice is not a container, it is simply a framework. In my uses of Spring, I've always brought Spring up at startup, and if any object needs DI, then every dependency between that object and the Spring root needed to be Spring managed. Guice's simplicity tempts me to just create new Injectors at the point in the object graph where they are needed, eventually having several injectors throughout the object hierarchy. I deal a lot with legacy code, and I've so far been stymied with how to use Spring without the dreaded Big Refactoring. I guess there's nothing stopping me from creating a whole bunch of Spring BeanFactories everywhere, but the prospect sounds a lot more appealing in Guice because it's a little lighter weight. If anyone has a DI in Legacy Code case study then send it my way.

As a sidenote, part of the Guice type safety relies on Neal Gafter's Super Type Tokens, and I finally feel like I understand that idea. The book explains it very well.

The Aspect Oriented features of Guice look cool too. Striving for the 80/20 rule in AOP has lead Guice to a point where there isn't a RegEx like declaration of point cuts, but rather a nice, fluent, type safe way to declare them. The compiler checked Guice code:

bindInterceptor(
subclassesOf(Phone.class),
returns(only(Receiver.class)),
new PhoneLoggerInterceptor()
);
Looks a lot more manageable (yet less powerful) than the Spring pointcut:
@Pointcut("execution(* com.xyz.someapp.dao.*.*(..))")
especially after having recently suffered through a demonstration of Spring AOP that involved 15 minutes of fiddling with the pointcut while wondering why it wasn't working.

An entire chapter of the book was spent on using Guice in Struts2 and Wicket. I don't often write web apps and I've used neither of these technologies; however, I have to say, Struts2 looked very easy to get running with a minimum of boilerplate. Either all the Struts2 horror stories I heard were false or Guice really does bring a lot to the table for web frameworks. I also really admire that the book tells readers wanting more information to buy Struts2 in Action (from Manning) whileApress seems to have their own series of Struts2 titles. Not sure how that slipped past the editors...

The book ended with a discussion of DAO and persistence, some Guice recipes (covering many common errors and edge-cases), and some thoughts on the future of Guice. I love that the book references a future Guice enhancement as Google Code issue #39. I think my pet project that nobody uses has more than 39 issues.

So what's the conclusion? 5 hours of reading left me with a good working knowledge of Guice. Definitely worthwhile. That's my glowing endorsement.

The Book Itself
The point of Apress' firstPress imprint is to provide short, lower cost, print-on-demand or eBooks on emerging technologies. This one weighs in at 180 pages (large print, small pages) and costs either US$10 or US$19.99. I really like the idea of this imprint. Longer than a white-paper, easier than the 600 page reference manual. Have you checked the page count on Pro Spring 2? 1,000 pages, you gotta be kidding. Only a student has that kind of time on their hands. Also, the writing was above average. Conversational, fast paced, and the code examples weren't filled with attempts to showcase the wit of the author. Note to world: there is only one person I know of that has the skill to make a good code example funny. You're probably not him. Lastly, a co-worker said they thought the book felt flimsy and cheap, but I never noticed. It had been rattling around my motorcycle top-case for 3 days, so I blame my transport not the book.

The Small Gripes
There is no index. There should be an index. And it should err on the side of too lengthy. Also, the diagrams mostly confused me. I actually understand what scope widening injection is, but I still can't figure out the diagram describing it. Whatever, it doesn't matter. I just felt like I had to say something negative to appear fair.

The Disclaimers
Apress sent me the book for free with the agreement that I'd review it. So I'm incented to write a positive review. On the other hand, I work full-time for a competing publisher. So I'm incented to bag on the book. We checked with the lawyers (seriously) and they were fine with it. That should be enough for anyone!

And to all you future jurors...
Jury duty rocks. It's as close to a vacation as I've had recently. But please, if you're summoned, know your rights. As a juror it is your constitutional right to ignore bad laws, power hungry judges, and overzealous prosecutors through the use of jury nullification. And I wonder why I was dismissed from all the juries I was pulled for.