Having fun with GWT EntityProxies in JUnit tests

by Stefan

GWT comes with a nice feature called RequestFactory that provides a high level abstraction of client-server communication. This includes a mechanism for entity conversion which allows you to have, for instance, JPA-mapped entities in the backend and independent DataTransferObjects (called Entity Proxy)  in the presentation layer. The definition of the Entity Proxies looks like this:

package cleancodematters;

import com.google.gwt.requestfactory.shared.EntityProxy;
import com.google.gwt.requestfactory.shared.ProxyFor;

@ProxyFor(Pizza.class)
public interface PizzaProxy extends EntityProxy {
  void setName( String name );
  String getName();

  void setPrice( Double price );
  Double getPrice();

  boolean isOrdered();
  void setOrdered( boolean ordered );
}

Entity + Interface + Tests = Trouble

As you can see, the entities are in fact interfaces (and created and populated by the framework for you). This has some advantages. For example, GWT can internally track changes and only send deltas over the wire. However, things get complicated when it comes to testing. If you want to create an entity and populate it with two parameters you find yourself writing code like this for every test case:

	PizzaProxy pizza = mock( PizzaProxy.class );
	when( pizza.getName() ).thenReturn( "Funghi" );
	when( pizza.getPrice() ).thenReturn( Double.valueOf(6.99) );


Things get worse if you want to check values set to your entity by the class under test as you have to use something like Mockito’s verify() to check for a expected value. For example:

	@Test
	public void testPizzaServiceOrder() {
		PizzaProxy pizza = mock( PizzaProxy.class );

		pizzaService.order( pizza );

		verify( pizza ).setOrdered( true );
	}

What if I don’t care that my entities are interfaces?

The ideal solution of this not very readable code would be to be able to use the interface based entities like standard pojos. This can be achieved with some mocking magic behind the scenes. With a little helper class the test above can be rewritten with:

	@Test
	public void testPizzaServiceOrderCleanCode() {
		PizzaProxy pizza = PizzaProxyHelper.createProxy();
		pizza.setName( "Funghi" );
		pizza.setPrice( Double.valueOf(6.99) );

		pizzaService.order( pizza );

		assertTrue( pizza.isOrdered() );
	}

Note that PizzaProxy is still an interface – however, the code is much more readable now. Of course, this comes with a price. You have to prepare each proxy field of your proxy type in the helper factory class. However, this only needs to be done once. Here’s the code:

package cleancodematters;

import static org.mockito.Matchers.any;
import static org.mockito.Matchers.anyString;
import static org.mockito.Mockito.doAnswer;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.when;

public class PizzaProxyHelper {
  public static PizzaProxy createProxy() {
    PizzaProxy pizza = mock( PizzaProxy.class );
    handleName( pizza );
    handlePrice( pizza );
    return pizza;
  }

  private static void handleName( PizzaProxy pizza ) {
    PropertyStorage<String> storage = PropertyStorage.create();
    doAnswer( storage.createSetterAnswer() ).when( pizza ).setName( anyString() );
    when( pizza.getName() ).thenAnswer( storage.createGetterAnswer() );
  }

  private static void handlePrice( PizzaProxy pizza ) {
    PropertyStorage<Double> storage = PropertyStorage.create();
    doAnswer( storage.createSetterAnswer() ).when( pizza ).setPrice( any( Double.class ) );
    when( pizza.getPrice() ).thenAnswer( storage.createGetterAnswer() );
  }
}

package cleancodematters;

import org.mockito.invocation.InvocationOnMock;
import org.mockito.stubbing.Answer;

@SuppressWarnings("unchecked")
public class PropertyStorage<T> {
  private T property;

  public static <T> PropertyStorage<T> create() {
    return new PropertyStorage<T>();
  }

  public Answer<Void> createSetterAnswer() {
    return new Answer<Void>() {
      public Void answer( InvocationOnMock invocation ) throws Throwable {
        property = (T) invocation.getArguments()[0];
        return null;
      }
    };
  }

  public Answer<T> createGetterAnswer() {
    return new Answer<T>() {
      public T answer( InvocationOnMock invocation ) throws Throwable {
        return property;
      }
    };
  }
}
Advertisements
Tags: , ,

2 Comments to “Having fun with GWT EntityProxies in JUnit tests”

  1. All these articles about unit testing in GWT are great inspiration for me, good work.

    I’m playing with mocking of EntityProxies according to this article. I’ve found one issue. If you try to pass mocked proxy as an argument to some request, you’ll get IllegalArgumentException from AbstractRequestContext.checkStreamsNotCrossed.

    E.g.

    EmployeeProxy empl = EmployeeProxyHelper.createProxy();
    empl.setEmail(“test”);
    empl.setName(“Foo Bar”);
    requestFactory.employeeRequest().getCurrentPerformancePlan(empl);

    I’m unable to test theese sections by any other way.

  2. Ok, I use approach from RequestFactory article and it’s working :-). Trying to allow passing mocked entityproxy to request would be much (maybe impossible) work.

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 )

Google+ photo

You are commenting using your Google+ 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 )

Connecting to %s

%d bloggers like this: