Organizing GWT Tests

[tag]GWT[/tag] (Google Web Toolkit) is one of the many excellent libraries/frameworks/APIs coming out of [tag]Google[/tag]. It is open source. All its source code is available under Apache 2.0 license (I can almost hear your sigh of relief :) ). So let me repeat! It’s open source as we understand it :). If you’re not familiar with GWT and if you’re in the business of developing Web applications, I strongly recommend knowing about it. But I’m not going to give an introduction to GWT in this article. There are a few good books out there (I own a copy of GWT in Action and it is an excellent one), the online documentation isn’t too bad (even though I must admit that I’ve mostly used my book) and the user group is very very active with almost 10,000 users as of this writing.

In this article, I want to talk about [tag]unit testing[/tag] GWT applications and I want to talk about specifically how to organize such tests.

GWT comes with unit testing support. Hmmm… Maybe I should rephrase that. GWT comes with testing support based on a popular unit testing framework. Actually, given the fact that GWT is a Rich Internet Application development framework, I must say that GWT comes with exceptionally good testing support. Testing GWT applications is a bliss compared to working with tools like JavaScript Debugger or JavaScript Shell. And it is not surprising that the GWT development team decided to harness the power of JUnit rather than reinventing the wheel. Even though they are based on JUnit, GWT tests don’t feel like the regular unit tests because they have an initialization penalty (On my machine it takes about 10 seconds). Probably, the in-container test analogy is better suited for GWT tests.

GWT’s JUnit integration is based on a class called [tag]GWTTestCase[/tag]. As you can guess, this class extends the JUnit TestCase and acts as a super class for the GWT tests that the developers write. For more information, you can have a look at the JUnit Integration section of the online documentation.

One of the handy tools that come with GWT is the [tag]junitCreator[/tag] utility. This tool generates a GWTTestCase and several scripts to run tests in both hosted mode and web mode.

For example, I’m going to create a new GWT component called ImagePanel. I’m doing my best to be a good Test-Driven Development practitioner ;) so I create the test first with the following command:

junitCreator -junit c:pathtojunit.jar -module module_name -eclipse MyProject ie.dsi.gwtapp.client.ImagePanelTest

A few points about the command shown above.

  • -eclipse is an optional command that you can use if you’re developing with Eclipse.
  • This command will create the script files in the current folder. If you want them somewhere else, you can use the -out parameter. I run the command from the project root directory so that’s where the script files appear for me.

Then, I can continue to develop. And I’m happy with this solution because now I can run the ImagePanelTest from within Eclipse using JUnit. It’s true that GWT tests aren’t executed as fast as real unit tests but this is so much better than what I can get with another RIA framework, I’m happy to live with it.

When I need to create another GWT component, let’s say HistoryTable, I can use the same command to create HistoryTableTest class. This would create a new set of script files (HistoryTableTest-hosted.cmd, HistoryTableTest-hosted.launch, HistoryTableTest-web.cmd, HistoryTableTest-web.launch). Do I really need to create these files every time I need to create a GWT test? Not really!

What you can do, is to create a GWT test suite in the beginning. When you write your first test, let’s say in the case of ImagePanel, rather than creating ImagePanelTest, you can create a generic test class called GWTTestSuite. In the generated code, you can add the following static method:

public static Test suite() {
  TestSuite suite = new TestSuite();
  return suite;
}

And when you create a new GWT test, you can add its declaration in this method:

public static Test suite() {
  TestSuite suite = new TestSuite();
  suite.addTestSuite(ImagePanelTest.class);
  suite.addTestSuite(HistoryTableTest.class);
  return suite;
}

This way, you use the junitCreator tool once to create only one set of script files. Then you can run your GWT tests together.

However, as a conscientious developer, you strive to create simple JUnit tests when possible. Those simpler tests don’t need the GWT initialization so they don’t need to be GWT tests at all. Obviously, following the last advice, you can create a static suite for these tests as well and run them separately but it becomes tedious to manually add each test in these suites. Fortunately GSBase library comes to our rescue. Using [tag]GSBase[/tag]’s RecursiveTestSuite class and TestFilter interface, it is possible to write a dynamic suite that’s going to scan a given directory and include all the tests automatically:

public class DynamicTestSuite {

  public static Test suite() throws Exception {
    return new RecursiveTestSuite("bin", new TestFilter() {
      public boolean accept(Class theTestClass) {
        return true;
      }
    });
  }

}

Now, we have a dynamic test suite that runs all the tests in the “bin” directory and its subdirectories. But do we want to run all the tests? What if we have abstract test classes? Or do we want to categorize our tests in a more practical way?

What we can do here is to create two dynamic test suites. One looks like the DynamicTestSuite shown above initially created by junitCreator so that the testing environment is set by the .launch or .cmd file. And, we can tag the GWT tests using a marker interface called GWTTest:

public interface GWTTest {}

Now when we create our ImagePanelTest, the class declaration looks like:

public class ImagePanelTest implements GWTTest {
...
}

And a quick modification to the DynamicTestSuite allows it to select only GWT tests:

public class DynamicTestSuite {

  public static Test suite() throws Exception {
    return new RecursiveTestSuite("bin", new TestFilter() {
      public boolean accept(Class theTestClass) {
        return (GWTTest.class.isAssignableFrom(theTestClass));
      }
    });
  }

}

Now we have a dynamic test suite that runs all the tests tagged as GWTTest. We can apply the same principle to create a QuickTestSuite that runs all the regular JUnit tests that don’t depend on GWT. This time we don’t need to use junitCreator tool.

public class QuickTestSuite {

  public static Test suite() throws Exception {
    return new RecursiveTestSuite("bin", new TestFilter() {
      public boolean accept(Class theTestClass) {
        boolean classIsConcrete = ! Modifier.isAbstract(theTestClass.getModifiers());
        boolean classIsNotGWTTest = ! GWTTest.class.isAssignableFrom(theTestClass);
        return classIsConcrete && classIsNotGWTTest;
      }
    });
  }

}

Summary

It is important to have unit tests. But it’s also important to have a practical working/testing environment that makes the TDD easy. Each small step taken in that direction helps in adopting unit testing. GWT has an exceptional testing support for a RIA development framework but we can make it more developer-friendly with a few additions: Tagging GWT tests and creating separate dynamic test suites are such additions. Let me know what you think about the approach described above and how we can improve it.

- Yagiz Erkan -

Listening to metallica mp3 (by RealPlayer Windows WordPress Plugin)

  1. #1 by Yagiz Erkan on November 12, 2007 - 5:28 pm

    While using the junitCreator tool, be careful to use the fully qualified module name. If you’re getting an error that says “Unable to find xxx.gwt.xml on your classpath” when you run your GWT tests, it may be that you specified a wrong module name, such as “EmailApp” instead of “my.company.client.EmailApp”.

  2. #2 by sanshi2 on December 21, 2007 - 1:48 am

    When I run the test got the error below ,why?
    weathertest is the test class I run .

    .Getting bytecode for ‘com.css.wwl.weathertest’
    [WARN] Unable to find compilation unit for type ‘com.css.wwl.weathertest’
    Getting bytecode for ‘com.css.wwl$weathertest’
    [WARN] Unable to find compilation unit for type ‘com.css.wwl’
    Getting bytecode for ‘com.css$wwl$weathertest’
    [WARN] Unable to find compilation unit for type ‘com.css’
    Getting bytecode for ‘com$css$wwl$weathertest’
    [WARN] Unable to find compilation unit for type ‘com’
    [ERROR] Unable to load module entry point class com.css.wwl.weathertest (see associated exception for details
    java.lang.ClassNotFoundException: com$css$wwl$weathertest
    at com.google.gwt.dev.shell.CompilingClassLoader.findClass(CompilingClassLoader.java:342)
    at java.lang.ClassLoader.loadClass(ClassLoader.java:289)
    at java.lang.ClassLoader.loadClass(ClassLoader.java:235)
    at java.lang.ClassLoader.loadClassInternal(ClassLoader.java:302)

  3. #3 by Yagiz Erkan on December 21, 2007 - 3:07 pm

    Strange… Are you using GWT 1.4?

  4. #4 by sanshi2 on December 24, 2007 - 5:12 am

    Version 1.4.61

    It’s OK after I move the class to “client” package.

  5. #5 by Alx Dark on January 5, 2008 - 8:32 pm

    Thanks for the article, this is great information. Without it you really can’t make the most out of GWT’s junit support.

  6. #6 by Yagiz Erkan on January 7, 2008 - 4:03 pm

    Thanks Alx,

    I’m glad that you find it useful…

  7. #7 by eytan on August 22, 2008 - 5:06 pm

    Thanks for this article. One problem that I had was that the GWT compiler was complaining with the following error:

    >>No source code is available for type junit.framework.TestSuite; did you forget to inherit a required module?

    I read on some forums that a solution to this problem is putting the GWTTestSuite in a directory that does not get compiled by the GWT compiler. However, when I move the suite to another directory, GWT compiler complains that it cannot find the required modules. Do you have any suggestions?

  8. #8 by Yagiz Erkan on August 26, 2008 - 10:33 am

    Hi eytan,

    You shouldn’t get these errors normally.

    Did you use the junitCreator to create the first test? Do you have the following files:
    xxxTest-hosted.launch
    xxxTest-hosted.cmd
    xxxTest-web.launch
    xxxTest-web.cmd?

  9. #9 by Yahoouj on February 14, 2010 - 1:11 am

    Really good work about this website was done. Keep trying more – thanks!

  10. #10 by CiarĂ¡n on October 2, 2010 - 12:21 pm

    Interesting article, I most look into unit testing in GWT more as I use GWT quite a lot. Thanks again

Leave a Reply

Please log in using one of these methods to post your comment:

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

Follow

Get every new post delivered to your Inbox.

%d bloggers like this: