Guice + EasyMock = Flexible Testable Code

Dependency injection and mock object testing are great practices on their own.  When used together your code ends up being very flexible and testable.  In this article we’ll use Guice and EasyMock.

When you design your system to use DI you end up with lots of interfaces that provide specific services, concrete implementations of those interfaces, and classes that depend on those interfaces.  Let’s pretend we’re building a web app that lets users find restaurants in their area and write reviews for them.  One little feature we just added lets the user share their love for a particular restaurant on Twitter.  There are several Java libraries for the Twitter API but we want our code to be really simple and not depend on any specific library.  Thus we create the Twitter interface (and a concrete implementation that wraps one of those Twitter Java libraries):

public interface Twitter
{
    public void update(Credentials credentials, String status);
}

Next we create the class that does the sharing.  This would probably respond to some kind of AJAX call from the browser – the specifics don’t really matter here.  The important thing is that we’re using Guice to inject two dependencies into this class’s constructor: a Twitter object that wraps some Twitter Java library, and a Credentials object that stores the current user’s Twitter username and password or OAuth tokens.

public class Share
{
    private Twitter twitter;
    private Credentials credentials;

    @Inject
    public Share(Twitter twitter, Credentials credentials)
    {
        this.twitter = twitter;
        this.credentials = credentials;
    }

    public void share(Restaurant restaurant)
    {
        twitter.update(credentials, "I loved eating at " + restaurant.getName() + "!");
    }
}

To properly unit test this class we really don’t want to be making real HTTP requests to Twitter’s API and then use their API to assert that the user’s status was actually updated with the correct content (that would be more of an integration test).

Instead we should completely isolate this Share class from everything around it, control the inputs to it and assert that is performing the correct behavior.  This is where mock objects come in handy.

public class ShareTest
{
    private Share share;
    private Twitter twitter;
    private Restaurant restaurant;
    private Credentials credentials;

    @Before
    public void setup()
    {
        twitter = createMock(Twitter.class);
        restaurant = createMock(Restaurant.class);
        credentials = new Credentials("username", "password");
        share = new Share(twitter, credentials);
    }

    @Test
    public void testShare()
    {
        expect(restaurant.getName()).andReturn("Mucho Burrito");
        twitter.update(credentials, "I loved eating at Mucho Burrito!");

        replay(restaurant, twitter);
        share.share(restaurant);
        verify(restaurant, twitter);
    }
}

Because we followed proper DI principles and hid the Twitter Java library behind an interface, we can easily provide our own mock Twitter object and totally control it (so no HTTP requests are made).  We use EasyMock in the setup() method to create the mock Twitter object and give it to the new Share object.  Then in the testShare() method we specify the calls we expect on our mocks and call the share() method.

Just by using DI with interfaces and constructor injection, we made our Share class easy to test.  EasyMock then gave us a great way to create the mock objects that isolate the Share class from its dependencies and properly unit test it.

Advertisements

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s