November 22, 2014
Hot Topics:

Guicing Up Your Testing

  • June 21, 2007
  • By Dick Wall
  • Send Email »
  • More Articles »

Getting Guiced

This is where Guice is a perfect fit. It allows you to define a configuration up front that maps implementations of objects to some method of looking them up. When you ask Guice for an object, it will not only look up the one you intend to use within your current context, but will also go through the object looking for dependencies it needs, and injecting the right instances of those objects for your current context as well. It will do this all the way through the chain, basically auto-wiring your objects into a running system without your having to pass parameters all through the application by hand.

Getting and using Guice is easy. Just go to http://code.google.com/p/google-guice/ and download the guice-1.0.zip file from there (or whatever the latest version is when you read this article). Unpacking the zip file will give you a bunch of jar files. The one you need for now is guice-1.0.jar.

You will need to add this one jar file as a library to your project. The IDE doesn't matter, and I will assume you know how to add a library. Incidentally, the sources provided with this article use the latest milestone build of NetBeans 6.0 (which has come on in leaps and bounds recently), but you should be able to adapt the sources provided to work in any IDE you care to (you will also need JUnit to run the unit tests).

Once the library is added to your project, using Guice is really easy. It is really just a collection of annotations for classes and a simple API for configuring the modules to wire up objects correctly. There is a bit more to it, of course (particularly when you start exploring some of the other Jars in the zip file), but ignore all that for now and just concentrate on the core features.

Getting Back to the Example

So, you know what your example looks like on the database, and you know how you can manually test around that, but what does the example look like on Guice?

You can get the full source code for this Guiced up example by downloading the project zip file.

First up, you want to let Guice know that it has some work to do on the Invoice class. In particular, you want Guice to provide the TaxRateManager to your Invoice for us when you create a new one.

Guice actually can perform three different kinds of injection: constructor, field, and method. There are situations where each of the three are useful, but for this example you will use the constructor injection.

import com.google.inject.Inject;

   private Customer customer;
   private List<Item> lineItems;
   private final TaxRateManager taxRateManager;

   /** Creates a new instance of Invoice */
   @Inject
   public Invoice(TaxRateManager taxRateManager) {
      this.taxRateManager = taxRateManager;
      // set up the line item list
      this.lineItems = new ArrayList<Item>();
   }

   public void setCustomer(Customer customer) {
      this.customer = customer;
   }

The changes here include importing the Inject annotation from com.google.inject.Inject, and the new @Inject before the constructor of Invoice. The eagle eyed among you will notice a regression in the code style as well: Customer is no longer passed in to the constructor at all, but is instead set via a modifier method. By doing this, it has been necessary to drop the final from the attribute definition as well. This is a bit of a step backwards, but I will come back to that later.

For now, though, you can see that you have made fairly minor changes overall to the class, but that the new @Inject is the most important thing to notice. This is a hint to Guice to "get involved" with the constructor of this class. It is still possible to create and use an instance this class just has you always have, but if Guice is used to create an instance, it proceeds as follows:

  1. It sees the @Inject annotation before the constructor.
  2. It looks at the type signature of the constructor parameters.
  3. For each of the parameters passed in to the constructor, it attempts to find a suitable implementation instance to pass in automatically for that parameter using a variety of rules.
  4. There is no Step 4. (Well, okay, there is, sort of—if Guice can't work out a concrete instance to pass in for a parameter, it will issue an error that, hopefully, will help you track down the problem.)

All this looks like magic, but it isn't; you just haven't completed your responsibilities yet. If Guice made this work as it stands, it would indeed be magic because you haven't given it enough information yet to know what to use for the TaxRateManager parameter. Beyond that, you haven't put it in control yet either (told Guice that you want it to do something). You'll look at those pieces next.

Binding Configuration

First up, explain to Guice what you want it to do when it sees a request to inject a TaxRateManager into something (remember that TaxRateManager is an interface, not a concrete implementation, so it has to create something real to use there).

To do this, you create a configuration module with a binding in it:

import com.google.inject.Binder;
import com.google.inject.Module;

public class TaxRateTestingModule implements Module {

   public void configure(Binder binder) {
      binder.bind(TaxRateManager.class).to(FakeTaxRateManager.class);
   }

}

That's it! This creates a specialization of Module that explains to Guice that when you see a TaxRateManager class, what you really want (at least for your testing purposes) is an instance of FakeTaxRateManager. In production, you could have another module that specified a DbTaxRateManager instead. This is where the auto-wiring blueprint comes from. Of course, a real system is likely to have a lot more such bindings defined, in which case you just need more binder.bind calls to define them. A lot of the errors you will see in a large Guice system are likely to be related to missing bindings, and hopefully the error reports are good enough to make it obvious which ones are missing.

One more quick thing: I mentioned earlier that using just a single instance of the TaxRateManager implementation would probably be a good idea, but that creating a typical static style singleton is too limiting (or too hard-wired) for good testing. Guice comes to your rescue here as well by providing a Singleton "scope" for your implementation binding. This can be applied two different ways:

One way is to add another call chained on to the binder.bind so it looks like this:

binder.bind(TaxRateManager.class).to(FakeTaxRateManager.class)
   .in(Scopes.SINGLETON);

where Scopes is another class imported from com.google.inject.

The other way (and the way used in the source code example) is to add an @Singleton annotation to the FakeTaxRateManager implementation:

@Singleton
public class FakeTaxRateManager implements TaxRateManager {

Both ways have advantages and disadvantages, and it's largely a matter of preference which one you will use. I prefer the latter way because it stores the semantic intent that the FakeTaxRateManager is a single instance in the system right there with the definition of the concrete class.





Page 3 of 5



Comment and Contribute

 


(Maximum characters: 1200). You have characters left.

 

 


Enterprise Development Update

Don't miss an article. Subscribe to our newsletter below.

Sitemap | Contact Us

Rocket Fuel