Zach's Blog

Just another WordPress.com weblog

Posts Tagged ‘activeobjects

ActiveObjects + EasyMock + Guice

leave a comment »

In the last post we saw how using Guice for dependency injection and EasyMock for mock objects produces a well-designed system that is easy to unit test.  In this post I’ll describe how the ActiveObjects ORM fits in nicely with these other tools.

When using ActiveObjects, each database table is represented by a Java interface, called an entity.  Each column in the database corresponds to get/set methods in the interface.  Individual rows in the table correspond to instances of the interface.  For example, here is a very simple AO entity for a restaurants table:

import net.java.ao.*;

public interface Restaurant extends Entity
{
    public String getName();
    public void setName(String name);

    public String getAddress();
    public void setAddress(String address);

    public String getPhone();
    public void setPhone(String phone);

    public int getTableCount();
    public void setTableCount(int tableCount);
}

Since every entity is an interface, they are incredibly easy to mock.  We saw this in the last example, where the Restaurant object was mocked and then we specified an expectation for its getName() method:

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);
    }
}

In a strict definition of unit testing, you should not be accessing a database at all.  The code that you are testing should be completely isolated from everything around it.  By mocking the AO entities in our code, we do not have to deal with databases at all in our unit tests.  (Testing your code with a database is also a good idea though – for that I recommend DbUnit).

AO provides a class called EntityManager that you use to create new entities or query the database for existing entities.  While you can mock an EntityManager using the EasyMock Class Extension in your unit tests, I actually create an IEntityManager interface that duplicates EntityManager’s API, along with a few extra convenience methods.  Any class that needs to create or find entities gets an instance of IEntityManager injected to its constructor (via Guice, of course).  The unit tests for that class then just mock the IEntityManager and pass it into the constructor when creating the instance in the setup() method.

In our restaurant review site, we want to provide a way for users to add new restaurants to the system.  On the back-end we need to take the user’s input (from an HTML form submit) and create a new Restaurant entity.  Let’s assume we use the following class to create a new restaurant:

import com.google.inject.*;

public class CreateRestaurant
{
    private IEntityManager manager;

    @Inject
    public CreateRestaurant(IEntityManager manager)
    {
        this.manager = manager;
    }

    public void create(String name, String address, String phone, int tableCount) throws SQLException
    {
        Restaurant restaurant = manager.create(Restaurant.class);
        restaurant.setName(name);
        restaurant.setAddress(address);
        restaurant.setPhone(phone);
        restaurant.setTableCount(tableCount);
        restaurant.save();
    }
}

Unit testing this class is a simple matter of mocking IEntityManager and Restaurant entities and asserting that proper methods are called on them in the create() method:

import static org.junit.Assert.*;
import static org.easymock.EasyMock.*;
import java.sql.*;
import org.junit.*;

public class CreateRestaurantTest
{
    private IEntityManager manager;
    private Restaurant restaurant;
    private CreateRestaurant creator;

    @Before
    public void setUp() throws Exception
    {
        manager = createMock(IEntityManager.class);
        restaurant = createMock(Restaurant.class);
        creator = new CreateRestaurant(manager);
    }

    @Test
    public void testCreate() throws SQLException
    {
        String name = "Mucho Burrito";
        String address = "50 Mapleview Dr W Barrie, ON L4N 9H5";
        String phone = "(705) 739-6824";
        int tableCount = 15;

        expect(manager.create(Restaurant.class)).andReturn(restaurant);
        restaurant.setName(name);
        restaurant.setAddress(address);
        restaurant.setPhone(phone);
        restaurant.setTableCount(tableCount);
        restaurant.save();

        replay(manager, restaurant);
        assertSame(restaurant, creator.create(name, address, phone, tableCount));
        verify(manager, restaurant);
    }
}

Again, we exploited the fact that the CreateRestaurant class only uses instances of AO interfaces to make unit testing extremely simple & contained.

import static org.junit.Assert.*;
import static org.easymock.EasyMock.*;

import java.sql.*;

import org.junit.*;

import com.pongr.ao.*;

public class CreateRestaurantTest
{
private IEntityManager manager;
private Restaurant restaurant;
private CreateRestaurant creator;

@Before
public void setUp() throws Exception
{
manager = createMock(IEntityManager.class);
restaurant = createMock(Restaurant.class);
creator = new CreateRestaurant(manager);
}

@Test
public void testCreate() throws SQLException
{
String name = “Mucho Burrito”;
String address = “50 Mapleview Dr W Barrie, ON L4N 9H5″;
String phone = “(705) 739-6824″;
int tableCount = 15;
expect(manager.create(Restaurant.class)).andReturn(restaurant);
restaurant.setName(name);
restaurant.setAddress(address);
restaurant.setPhone(phone);
restaurant.setTableCount(tableCount);
restaurant.save();

replay(manager, restaurant);
assertSame(restaurant, creator.create(name, address, phone, tableCount));
verify(manager, restaurant);
}
}

Written by Zach Cox

June 8, 2009 at 11:28 am

Posted in Java

Tagged with , ,

Follow

Get every new post delivered to your Inbox.