http://www.developer.com/

Back to article

Guicing Up Your Testing


June 21, 2007

In what I hope will be the first of several articles about Guice, a new lightweight dependency injection container from Bob Lee and Kevin Bourrillion from Google, this article examines the simplest and most obvious use case for the Guice container, for mocking or faking objects in unit tests. In future articles I will examine other, more ambitious areas where it can be used, including dependency elimination in large code bases.

If you are familiar with the idea of mock or fake objects, this article may seem like slow going (apart from the Guice parts, hopefully). However, if you have not used mock or fake objects before, this article will not only cover their use, but demonstrate how these techniques go hand-in-hand with dependency injection.

The Test Case

To illustrate the use of Guice, you need an example unit testing setup. I settled on something pretty simple—an invoice class that uses a sales tax rate manager (another object) to look up a sales tax percentage for a customer. The invoice then adds it on to the total sum of the line item costs in the invoice.

The twist is, you are going to pretend that the tax rate manager looks up the tax rate for a customer based on the customer ID (say it varies depending on their state, which is information that the tax rate manager gets from the customer ID). You'll also throw in there that the poor old database backing this tax rate lookup is overloaded, and takes around five seconds for any query or update operation (this really isn't much of a stretch for a large and heavily used database—believe me).

Your test objects might look something like this:

public class Invoice {

   /** A Simple public inner and immutable class to hold line items
    * for the invoice, including the title, description and cost
    */

   public class Item {
      private final String title;
      private final String description;
      private final BigDecimal cost;

      .... (constructors and getters here)
   }

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

   public Invoice(Customer customer) {
      this.customer = customer;
      // set up the line item list
      this.lineItems = new ArrayList<Item>();
      this.taxRateManager = DbTaxRateManager.getTaxRateManager();
   }

   public void addItem(String title, String description, double amount) {
      lineItems.add(new Item(title, description, amount));
   }

   private BigDecimal getTotal() {
      BigDecimal runningTotal = new BigDecimal(0);
      for (Item item:lineItems) {
         runningTotal = runningTotal.add(item.cost);
      }
      return runningTotal;
   }


   public BigDecimal getTotalWithTax() {
      BigDecimal total = this.getTotal();

      // now find the tax rate for the customer
      BigDecimal taxRate =
      this.taxRateManager.getTaxRateForCustomer(
         customer.getCustomerId());

      // and calculate the taxed total
      BigDecimal multiplier = taxRate.divide(new BigDecimal(100));

      // Boy, Big Decimal might be accurate, but it certainly is
      // ugly to do math with...
      return total.multiply(multiplier.add(new BigDecimal(1)));

   }
}

The rest of this class, along with the supporting object classes, can be seen by downloading the project zip file.

Take a look at this implementation. From the constructor, observe the line:

this.taxRateManager = DbTaxRateManager.getTaxRateManager();

This is getting the tax rate manager instance from a pretty standard mechanism in many modern implementations: a singleton. I personally believe the singleton pattern, at least in the way most people implement it (using a static getter method and a single private internal instance) to be one of the most harmful patterns from the Gang of Four book (and the numerous other patterns authorities out there). A singleton implemented this way is particularly harmful because it is very easy to grasp, and very seductive, but results in unintended consequences in many different areas.

In this particular case, the singleton implementation of DbTaxRateManager means that any time you create an invoice, you are bound to that implementation of the tax rate manager. This is the point of a singleton—it makes it dead easy to get the tax rate manager and use it, but beyond that it pretty much sucks.

For example, when you want to test this simple invoice class, that test is going to use the DbTaxRateManager implementation. This means it is going to hit the database, and with your stated database performance, this means about 5 seconds per update or query.

Further down, in the GetTotalWithTax method, you see the following usage:

BigDecimal taxRate =
   this.taxRateManager.taxRateForCustomer(customer.getCustomerId());

That's 5 seconds gone right there in that one lookup. Now, if you look in the test class:

private static final int CUST1_ID = 12341234;
private static final int CUST2_ID = 43214321;

@Before
public void setUp() throws Exception {
   // set up a couple of customer IDs with tax rates we can use
   DbTaxRateManager taxRateManager=DbTaxRateManager.getTaxRateManager();
   taxRateManager.setTaxRateForCustomer(CUST1_ID, 5.5);
   taxRateManager.setTaxRateForCustomer(CUST2_ID, 6.25);
}

Here, you have set up a couple of fake customer IDs and put them into the database with two different tax rates. Two updates, another 10 seconds.

So, by running this test, best case (doing only one tax lookup and the two rate assignments), the test is going to take over 15 seconds to run. Imagine a thousand unit tests that take 15 seconds each; you are going to be waiting a while.

That singleton is killing you performance-wise. There are all sorts of schemes to improve this situation. Some people recommend running some kind of alternative, lightweight alternative database and changing the database connection details (for example, for some functional testing, Derby or JavaDB are becoming a popular option).

Simple Dependency Injection

The simplest solution is to get rid of the reliance on that singleton. To test the invoice class, there is no reason you need a real database to back it (even if it is a fast one). Look at what you need out of the DbTaxRateManager. There are only two methods you need: setTaxRateForCustomer, and getTaxRateForCustomer. These take a customer ID and return a double. That sort of functionality can be supplied by a hashmap just as easily as a database, and it's faster and lighter too.

Producing a class implemented like this that simulates the desired functionality from the database implementation is known as faking the object (rather than mocking the object, which is more akin to providing a script that the mock object is expecting to follow, and then following it). Either way, the point here is to test the Invoice class and its calculation of sales tax on a number of items rather than the TaxRateManager, so if you assume that the TaxRateManager just stores and retrieves sales tax percentages based on a customer ID, you end up with something like this:

public class FakeTaxRateManager implements TaxRateManager {

   private Map<Integer,BigDecimal> taxRates;

   public FakeTaxRateManager() {
      taxRates = new HashMap<Integer, BigDecimal>();
   }

   public void setTaxRateForCustomer(int customerId, BigDecimal taxRate) {
      taxRates.put(customerId, taxRate);
   }

   public void setTaxRateForCustomer(int customerId, double taxRate) {
      this.setTaxRateForCustomer(customerId, new BigDecimal(taxRate));
   }

   public BigDecimal getTaxRateForCustomer(int customerId) {
      BigDecimal taxRate = taxRates.get(customerId);
      if (taxRate == null) taxRate = new BigDecimal(0;
      return taxRate;
   }
}

There are a couple of things to note here. First, this is a really simple class. More importantly, it stores everything in memory, never going near a database, so it is going to be really fast to use in a unit test (of course, nothing will be stored across tests, but you can set up everything you need in the unit test and in fact you should—unit tests should not rely on assumed state from some other test or run because that state can always be wrong).

The second thing to notice is that your new FakeTaxRateManager implements an interface called TaxRateManager. For your dependency injection to work, you need to create an interface that the Invoice class uses, rather than a specific implementation. The interface can be refactored out by most modern IDEs with just a few clicks, and should look something like this:

public interface TaxRateManager {

   public void setTaxRateForCustomer(int customerId, BigDecimal taxRate);
   public void setTaxRateForCustomer(int customerId, double taxRate);
   public BigDecimal getTaxRateForCustomer(int customerId);

}

Now, you just run through the Invoice class and replace references to DbTaxRateManager with references to the TaxRateManager interface.

Doing this brings all sorts of benefits beyond easy testability, and I will cover some of these in future articles, but in a nutshell, what you have done here is to eliminate an implementation dependency. Invoice no longer relies on a class that uses the Database. Instead it uses an interface, the implementation of which you don't care about as long as it fulfills the contract.

Of course, you can't run against an interface—somewhere along the way you need to have a specific implementation for TaxRateManager that does the work. For real life usage, that will be the DbTaxRateManager implementation, but for your testing you want to use the FakeTaxRateManager instead.

The easiest thing to do (without using something like Guice anyway) is to just pass the TaxRateManager implementation you want to use for the Invoice in to the constructor whenever you create a new Invoice object, something like this:

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

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

So now, when you create an invoice, in the real life situation you can pass in the database implementation of the TaxRateManager, and for testing you can pass in your fake one that is much faster.

If you can understand the above concept, you know all you need to know to grasp dependency injection. It's just a fancy way of saying "I will tell you what to use when I configure you".

So, if that's all there is to dependency injection, why do you need something like Guice?

Well, think about this. If you use this trick everywhere, in most instances of most classes in your application, what will that do to your code overall? For one thing, you are going to be doing a lot of passing around of injectable items throughout the application. When I want to make an Invoice somewhere in my application, I need a TaxRateManager implementation to pass in. I can either go and find one somehow (which is likely to cause the same kind of inflexibility as looking it up from within the Invoice class itself), or I can pass the TaxRateManager implementation I want to use in to the code that creates the Invoice, which means that needs to be either looked up or passed in from somewhere else, and so on. Pretty soon, all of our code is going to be dominated by loads of parameters being passed into constructors or method calls all over the place, and the code is going to get ugly.

Also, although the singleton implementation that most people use in Java applications is a nuisance, the concept of re-using a single TaxRateManager rather than creating a brand new one for each Invoice is still probably a good one. Barring concerns about thread safety or being a performance bottleneck, it is probably wasteful of memory (not to mention database connections in the case of the database implementation) to have a new DbTaxRateManager for every Invoice. You could pass around the exact same instance among all of the constructor and method calls, but no one can drop the ball or you will end up with multiple instances.

So, although passing in parameters solves one problem, that of concrete dependencies between class implementations, it introduces a lot more and is not really practical in a large scale application. This is why other patterns such as factories, directories, and so on have become popular; they provide you with some organized way to find and use an object instance that you require.

The problem with directories and factories is that they are heavy and usually a little complicated to set up. They are great in large, enterprise systems, but might be too heavy or bulky for small and light applications. Most of them use string naming lookup too, which carries its own risks (strings that are incorrect can't be caught by a compiler and will only show up at run time).

What you need is some easy and light way to "wire up" all of these inter-object dependencies at runtime. You should be able to specify the intent of what implementation is used under what circumstances in a configuration somewhere, and then let some library do the work of getting everything hooked up, be it for testing or a production run.

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.

Putting Guice in Charge

The other thing you still need to do is get Guice involved with the application setup. All of the pieces are in place now, but Guice hasn't been invoked or hooked in yet.

Here is a great rule that Zorzella and Sasha from Google came up with, and which is a good one to remember:

Guice is the new "new".

In other words, in a Guice application you won't see a lot of new() calls. If you create an object using new, there is no way for Guice to get involved. Instead, you use Guice to create an instance of the object you want. This causes the dependency injection to occur, and recur as deep as necessary to get your wired up system.

Take a look at the test setUp where all this happens:

@Before
public void setUp() throws Exception
   Injector myInjector = Guice.createInjector(new TaxRateTestingModule());

   taxRateManager = myInjector.getInstance(TaxRateManager.class);

   // set up a couple of customer IDs with tax rates we can use
   taxRateManager.setTaxRateForCustomer(CUST1_ID, 5.5);
   taxRateManager.setTaxRateForCustomer(CUST2_ID, 6.25);

   // also get an Invoice for testing
   invoice = myInjector.getInstance(Invoice.class);
}

The key lines here are:

   Injector myInjector = Guice.createInjector(new TaxRateTestingModule());

This creates an injector using the TaxRateTestingModule configuration binding you created (so that the injector knows what binds to what).

Then:

   taxRateManager = myInjector.getInstance(TaxRateManager.class);

This line gets you a taxRateManager to use in the test. Note that you ask Guice to get you a taxRateManager to use based on the Interface "TaxRateManager". You don't specify a concrete implementation, but the binding rules you created are used for that instead.

The next two lines set a couple of fake customer ID lookup rates using this taxRateManager instance you have. Because you specified that this should be a singleton, later on in the testing when the TaxRateManager is injected into the Invoice class, it will be the same one with these testing values available for the lookup.

Finally, there is a tricky one in there:

   invoice = myInjector.getInstance(Invoice.class);

You need Guice to give you the invoice to use so that it can inject the TaxRateManager into the Invoice so you can use it. But hang on, you didn't specify a binding for the Invoice class, so how does Guice know what to do?

Guice has a special rule for concrete class definitions. Because Invoice is actually a class, not an interface, Guice can make a pretty good guess that the instance you want is an instance of that class. However, by going through Guice to get this class rather than using new(), Guice has a chance to inject the TaxRateManager for you.

Now you have the invoice set up for testing using your fake (fast) TaxRateManager implementation. The actual test looks pretty similar, but there is one change necessary:

@Test
public void getTotalWithTax() {
   System.out.println("getTotalWithTax");

Customer customer = new Customer(); customer.setCustomerId(CUST2_ID); customer.setCustomerName("FredCo"); invoice.setCustomer(customer);
double expResult = 106.25; // Expected total with tax // add some line items invoice.addItem("Beach Ball", "Beach Ball in Multiple Colors", 37.55); invoice.addItem("Swimsuit", "Fashionable swimsuit, black", 62.45); BigDecimal result = invoice.getTotalWithTax(); assertEquals(expResult, result.doubleValue()); }

The highlighted code is the new stuff. If you remember, you pulled out setting the customer from the constructor into a modifier method. Before you can test the class, you need to set a customer for that invoice. These lines do exactly that.

Why is this necessary? Well, remember that Guice is the new "new". Because you don't call the constructor any more, you can't provide constructor parameters. Instead, you need another way to pass in the information.

Customer, in this case, could have been bound and injected as well, but if you think about it that doesn't really fit. What are the chances that all of the Invoices you create are going to be for the same customer? Heck, even in our little test, the most likely second test will be to test the tax rate calculation for the other customer!

So, using a setter is the easiest way around the problem, but it is definitely sub-optimal. Perhaps the biggest problem is the lack of finality: The customer can be changed on an existing Invoice—that doesn't sound particularly safe—it really should be immutable once set. You could add some code to check whether the customer has already been set for an Invoice and throw an exception if someone tries to reset it, but face it, this is all starting to smell like a bit of a hack.

Also, there is the very real risk that someone creating an Invoice will forget to set the customer on it. Your code is (deliberately) not particularly safe in this circumstance and will fail with a NullPointerException if someone tries to calculate the total with tax when the Customer has not been specified.

When writing this article, as I first hit this problem it blocked me for a while. It certainly made what was a nice clean demo into something a little less clean. As I thought about it, though, I realized that this problem had value in its own right. It drives home a very important point: Although dependency injection is a fantastic tool on many levels for improving code style and design, it is not a silver bullet. This problem of setting the customer for an invoice deserves a good solution, and that solution will come from a different angle than dependency injection.

It will also come in a later article, because I think you will agree this one is quite long enough already. You have also set out to do what you wanted to do as well, which is to isolate the unit testing of the Invoice class from the slow, database reliant, DbTaxRateManager.

So, hang tight and you will come back and fix the style issues in the next article, as well as starting to look at some of the other applications of Guice beyond testing.

The Proof is in the Pudding

So, after all this work, did you get a result? Well, take a look:

Running the original test, with a simulated 5 second turnaround for database queries and updates, you see the following result:

org.bldc.guicetestingdemo.InvoiceTest passed
   getTotalWithTax passed . 15.018 seconds

After using Guice to inject your fake implementation based on a HashMap, you see a more reasonable:

org.bldc.guicetestingdemo.InvoiceTest passed
   getTotalWithTax passed . 0.154 seconds

That's a couple of orders of magnitude improvement! Okay, this is a contrived example, but real world experience tells me this is not so far off. Eliminating dependencies on file I/O, databases, remote services, and so forth can cause a dramatic increase in the speed of unit testing. This means you can run more tests in less time, and that you are testing your class implementation and not the rest of a less-than-reliable stack (of course, remember that you can also simulate a less than reliable stack as well, forcing exceptions to be thrown that might occur in the real implementation—another advantage to faking or mocking your objects).

Conclusion

In this article, you have explored ways to use Guice to eliminate dependencies on slow implementations when unit testing an object and replace those slow implementations with faster fake ones. Although this is a good example usage of Guice, it is far from being a one trick pony. In future articles, I hope to explore what Guice means to a much larger architectural field, leading up to a particular interest of mine, that of splitting up large systems into smaller subsystems that can be built in total isolation from one another but still be wired up to run together when necessary.

This example is also intended for only one purpose: to show what Guice can do and how it does it. The implementation of Invoice, and of the fake tax rate manager, are both rather substandard because I wanted to concentrate on just demonstrating Guice and not get bogged down in other implementation details. In the next article, I will come back and clean up this example from just a simple speed focused improvement into something a lot better in terms of style and design.

About the Author

Dick Wall is a software engineer at Google, based in Mountain View. He also co-hosts the Java Posse podcast—a regular Java-centric news and interviews show that can be found at http://javaposse.com.

Special thanks to "Crazy" Bob Lee and Kevin Bourrillion for checking this article.

Sitemap | Contact Us

Thanks for your registration, follow us on our social networks to keep up-to-date