Dan Wellman's Blog

Testing JSON parsing using JavaScript Overlay Types in GWT 1.5

Bruce Johnson has posted a new entry on the Google Web Toolkit blog entitled Getting to really know GWT, Part 2: JavaScript Overlay Types. In the article, Bruce shows us how to use the new GWT 1.5 JavaScript overlay types to easily parse JSON into Java objects.

I previously wrote about Testing JSON Parsing with GWTTestCase using the original GWT JSON parsing libraries, so I'm posting a new example of testing JSON parsing using the new JavaScript Overlay Types.

Bruce's example parses some customer data into a Java Customer object. Here's the source from the article, with an additional "parse" factory method that parses a Customer object from a String containing JSON.

class Customer extends JavaScriptObject {

  // Overlay types always have protected, zero-arg ctors
  protected Customer() { }

  // Typically, methods on overlay types are JSNI
  public final native String getFirstName() /*-{ return this.FirstName; }-*/;
  public final native String getLastName() /*-{ return this.LastName; }-*/;

  // Note, though, that methods aren't required to be JSNI
  public final String getFullName() {
    return getFirstName() + " " + getLastName();
  }

  // Parse from JSON, based upon code from
  // http://sites.google.com/site/io/gwt-and-client-server-communication
  public static final native Customer fromJson(String input) /*-{
    return eval('(' + input + ')')
  }-*/;
}
Here's a simple test case demonstrating using an existing JavaScript object as well as parsing from JSON:
public class CustomerTest extends GWTTestCase {
  // Required by all GWTTestCases
  public String getModuleName() {
    return "JsniOverlays";
  }
 
  public void testUsesUnderlyingJavaScriptObject() {
  Customer customer = testCustomer();
    assertEquals("Jimmy", customer.getFirstName());
    assertEquals("Webber", customer.getLastName());
    assertEquals("Jimmy Webber", customer.getFullName());
  }

  // Sample test fixture
  private native Customer testCustomer() /*-{
    return { "FirstName" : "Jimmy", "LastName" : "Webber" }
  }-*/;
 
  public void testParsesFromJson() {
    Customer customer = Customer.fromJson("{ FirstName: \"Murphy\", LastName: \"Plankton\" }");
    assertEquals("Murphy", customer.getFirstName());
    assertEquals("Plankton", customer.getLastName());
  }
}

Notice that testUsesUnderlyingJavaScriptObject refers to a test fixture creation method written in JavaScript using JSNI. This test is similar to Bruce's example which coerces a JavaScript object into a Java object.

testParsesFromJson passes in a String containing JSON, which is what a remote service might do after receiving a response from a server. Notice how I'm not testing getFullName again in this test; it's already been verified in another test.

Testing Considerations

One challenge with using overlay types is that your objects contain JSNI -- which means that they fail to run in a plain JUnit TestCase. Instead, they must be run in a GWTTestCase, and that means a much slower test.

To solve this problem, I'm tempted to create an interface for the methods I need on my Customer object, then create a Test Double to use in my tests. This would encourage referring to the object by it's interface, which is a good thing.

Still, it seems a little annoying that I need to jump through some hoops so that my core domain object (Customer) doesn't accidentally call JavaScript in my tests. I'm not sure if this would be a real problem or not; experience will tell.

Congratulations to the GWT team on their hard work in making some great improvements to GWT 1.5!