Tuesday, May 6, 2008

Managing dependencies on the client side

So you're testing some GWT code. Ideally you've isolated some of the hard dependencies on GWT code so you can run these tests in pure JUnit. Unfortunately the code you're trying to test has hooks into some other code that's a little too coupled to GWT. This is a dependency problem - if we could replace the depended-on code with a Test Double, then we could better isolate the code we want to test.

On the server side, we're lucky - we have a good assortment of tools to help us in testing. One of the most common things we do in testing is using test doubles to isolate some code. (See Martin Fowler's Article for more info on test doubles). One of the best ways to get these test doubles into our system is to use dependency injection (Spring, PicoContainer, Guice, etc). Using these techniques allows us to isolate the code that we want to test - to put it in a little vice where we control what's being fed into it, and what it talks to.

Unfortunately, we don't have real reflection on the client, and we don't (currently) have dependency injection. Does this mean that we can't introduce test doubles? Well, no, but for now we'll take a more manual approach.

The approach I've taken is to use a Service Locator (or Dependency Lookup) approach. This means that instead of having all dependencies automatically wired up for us (via a constructor for example), we ask a service locator for them explicitly. This isn't optimal, but it's good enough, and lets us decouple our system a lot more than handing these around to anyone who will need them.

So - the question becomes - how can we replace these dependencies with test doubles? The answer is - easily, using some common approaches.

First off, just as in dependency injection, we program to interfaces in all client code. So if you have a GwtQuestionDialog implementation, you would program to a QuestionDialog interface:

QuestionDialog questionDialog = serviceLocator.getQuestionDialog();

Thus the service locator implementation that runs in GWT always returns the GWT instance, but we can provide the ability to inject an alternate test double for our tests.

An approach that I've found works is for the service locator (which can be a singleton) to hold on to a reference to the question dialog. If it's not created, it can create one, else it returns the reference. If the test installs a test double as the question dialog, the service locator will happily return it. I've created a test-specific subclass to override some setters for the service locator, to allow me to install these test doubles statically.

One does have to be sure to cleanup after each test, as these statics can leave undesired state around.

This simple approach should provide you with:
- A decoupled client-side codebase
- The ability to install test-doubles for depended upon components


--


An alternative (and interesting) approach is using GWT.create() exclusively on the client side instead of the new operator (this has limitations), and using JMockit in the tests to introduce the specific test doubles we're interested in. I'll talk about this in a later article.

Wednesday, April 23, 2008

Good links!

First off, let's start of with some good links for testing with GWT:

This is one of my new favorites, Rob describes approaches for developing UI's in GWT that are test driven. This uses a great approach of the MVC pattern paired with the Humble Dialog approach. This allows one to test most of the view code with lightening-fast JUnit (or any other xUnit) tests. Used appropriately, this is a huge advance in WebApp testing and productivity.

http://robvanmaris.jteam.nl/2008/03/09/test-driven-development-for-gwt-ui-code/

And a shorter GWT+MVC primer post by Iwein Fuld:
http://blog.springsource.com/main/2008/02/19/enabling-test-driven-development-in-gwt-client-code/

More to come!