In pursuit of code quality: Unit testing Ajax applications

unalaskaweepingInternet and Web Development

Jul 19, 2012 (5 years and 29 days ago)

501 views

In pursuit of code quality: Unit testing Ajax applications http://www.ibm.com/developerworks/java/library/j-cq07247/index.ht...
2 of 8 16/10/2007 11:19

If you enter in a valid word and click the
Submit button of this component, a message is sent to a server requesting
the word's definition. The definition is returned asynchronously through a callback and is accordingly inserted into
the Web page, as shown in Figure 2:
Figure 2. After clicking the Submit button, a response is displayed

Functional versus integration testing
Testing the interaction shown in Figure 2 can be broken out into a number of different scenarios, but two stand out.
From a functional standpoint, you'd probably want to write a test to fill in the form value, click the
Submit button,
and then verify the presence of the definition under the form. A second option would be an integration test, which
would allow you to validate the asynchronous functionality of the client-side code. The GWT's GWTTestCase
was designed for just this sort of test.
The thing to remember is that user interaction testing isn't possible with the GWTTestCase test case environment.
When designing and building GWT applications, you must think about testing the code without relying on user
interactions. This sort of thinking requires a decoupling of interaction code from business logic, which (as you
already know) is a best practice to begin with!
For example, take another look at the Ajax application shown in Figures 1 and 2. This application is composed of
four logical components: a TextBox for entering a desired word, a Button for clicking, and two Labels (one
for the TextBox and the other where the definition is displayed). An initial approach to the actual GWT module
could look like what you see in Listing 1, but how would you test this code?
Listing 1. A valid GWT application, but how to test it?
 
         !"# ##"# #!  !$%!&'  &' ! (  ) *! (  + ,- & + ,- (,./)0.

! (! (#! (12 12 12$-   -#(- "# !$ ,  $ (3 (- . !  (-
 4, 125"6$( %7(  -!8  9:  +  (  "#  +(  -!8
In pursuit of code quality: Unit testing Ajax applications http://www.ibm.com/developerworks/java/library/j-cq07247/index.ht...
4 of 8 16/10/2007 11:19
 6 ( # #(  + - 6=>!8  6 ( # #!88
I've now enabled programmatic access to all of my UI-related components (assuming that all the classes that
require access are in the same package). Only time will tell if I actually need to use one of these accessors for
verification purposes. I'm hoping to limit my use of the accessors because, as I've already mentioned, the GWT
isn't meant to be used for interaction testing. In this case, I'm not really trying to test whether a button instance has
been clicked, but rather that the GWT module will call my server-side code for a given word and that the server
side will return a valid definition. I do this by pushing (no pun intended!) the onModuleLoad() method's
definition-retrieving logic into a testable method, as shown in Listing 3:
Listing 3. The refactored onModuleLoad method defers to more testable methods
&'  &' ! (  ) * *! (  + ,- & + ,- (,./)0.

! 6 (- ! (!"# # ## 6 (- "# #! ( ##!   6 (-  ! (12 12 12$-    $!88! ( ! (  1+ ,-  4& + ,- (,./)09""9!; (-  * ?; (-  * ( !8   6 (- 9  !; (-   * ?; (-   * (  !88
As you can see in Listing 3, I've essentially deferred onModuleLoad()'s definition-retrieving logic to the
submitWord method, which is defined below in Listing 4:
Listing 4. The meat of my Ajax application!
    $ - 6 (- "# #(- "# ( ! 6 (-
 !8  -
  -$ ,  $ (3 (- . !  (-
 4, 125"6$( %7(  -!8
In pursuit of code quality: Unit testing Ajax applications http://www.ibm.com/developerworks/java/library/j-cq07247/index.ht...
6 of 8 16/10/2007 11:19
Functional testing with the GWT
A simple Ajax application like the one
demonstrated here could be verified from
a functional standpoint using a
framework like Selenium, which drives a
browser to simulate actual user behavior.
Now that I've got a module name, I can begin defining a test case as in Listing 5:
Listing 5. You must implement the getModuleName method and provide a valid name
 (--(- (: ( (/$"" 1 ! (--(- ( ( ("! $" #  /$"" 1  -- ) ((- ($!88
So far, so good, but I haven't tested anything yet! Because my Ajax application uses the AsyncCallback object,
I'll have to force JUnit to delay running to completion when I call the getDefinition() method via my test
case; otherwise, the test will fail due to no response. This is where GWT's Timer class comes in handy. Timer
allows me to override getDefinition()'s run method and finish the test case's logic within Timer instead.
(The test case will be run in separate thread, effectively blocking JUnit from completing the overall test case.)
For example, with my test, I'll first call the getDefinition() method and then provide an implementation of a
Timer's run() method. The run() method obtains the text of the output Label instance and verifies that the
proper definition is there. After I've defined a Timer instance, I then need to schedule it to launch while also
forcing JUnit to hang around for the Timer instance to complete. If this sounds complicated, don't worry, it's quite
easy in practice. In fact, you can see the entire scenario in Listing 6:
Listing 6. Testing with GWT is a cinch
 
 + 6 # $$!(-
 - !" " -(- 9  (- "# ! -  @-6 !(((!  @  67 4 4! 6" !88! ( 6=>>!" 5 6A>>!8
As you can see, the Timer's run() method is where I actually verify the functionality of my Ajax application
and its use of a remote procedure call. Note that the last step in my run method is to call the finishTest()
method, which signals that everything went as expected and JUnit should run as normal without further blocking.
In practice, you may find you'll need to hone your delay times further depending on how long the asynchronous
behavior requires to complete. But the point of testing GWT applications through JUnit is that you can do it
without having to deploy the fully functional Web application to test it. As a result, you can test your GWT
applications earlier and hopefully more often.
Running a GWT test
As I mentioned earlier, if you'd like to actually run your GWT JUnit
tests, you'll have to do a number of little things to configure a
running environment. For example, to run my tests via Ant's junit
task, I have to ensure some files are in my classpath and provide an
argument to the underlying JVM. Specifically, when invoking the
junit task, I need to ensure the directory (or directories) that hosts