In an attempt to orient myself and my colleagues with GWT, I've been reading up on GWT, trying things out, and blogging about them here. My goal is to start with simple use cases and build on to them with more complex ones. The way it's been working so far is that each post builds on the prior one.

Wednesday, February 17, 2010

Testing the View (Development Mode)

Now that we have a View implementation for the Contact List UI Component, it would be nice to see it rendered in a web page. We don’t have the full Contact List application ready so, at this point, we can only render the ContactListView implementation. Before starting to fill what’s needed to run this code, it will first be helpful to look at the anatomy of a GWT application:

image

For now, we’ll ignore the Production side of this diagram since we’re still filling out our development source, but feel free to refer back to it later as you look at the deployed application. To render a page that uses GWT-generated JavaScript, 4 primary things are needed in the development source:

  1. Client-side Java. This is what we’ve been building so far. The Models, Views, and Presenters were all part of the Client-Side Java which we ultimately want executed inside the browser as JavaScript.
  2. An Entry Point Java class, a class extending the GWT EntryPoint class. This is needed for any page that will execute GWT-generated JavaScript. It essentially bootstraps the page generating any initial HTML and wiring up all the event listeners to handle the user’s actions.
  3. A Module definition, an XML file that defines, among other things, what Java classes will be used to make up this JavaScript application.
  4. An HTML host page that will reference the GWT-generated JavaScript file.

To get this test started, we’ll initially build the ‘Entry Point’. For the ContactList UI Component, we have our View and Presenter implementations so the only things we need to mock for the View to be rendered are the Model objects.

	public void onModuleLoad() {

// wire up presenter with view implementation
ContactListViewImpl view = new ContactListViewImpl();
EventBus eventBus = new EventBusImpl();
ContactListPresenter presenter = new ContactListPresenter(view, eventBus);

// mock Contacts
Collection contacts = new ArrayList();
contacts.add(new ContactImpl("Jim"));
contacts.add(new ContactImpl("Joe"));
contacts.add(new ContactImpl("Jane"));

// apply contacts to view
presenter.setContactList(contacts);

// put contact list on page
RootPanel.get().add(view);
}


Next we’ll write our Module definition file. The Module definition file will be called ContactListTest.gwt.xml and looks like:



<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE module PUBLIC "-//Google Inc.//DTD Google Web Toolkit 2.0.0//EN" "http://google-web-toolkit.googlecode.com/svn/tags/2.0.0/distro-source/core/src/gwt-module.dtd">
<module>
<inherits name="com.google.gwt.user.User" />

<!-- Specify the app entry point class -->
<entry-point class='com.gwtdesign.mvp.contactlist.testui.ContactListTestEntryPoint'/>

<source path="client"/>
<source path="shared"/>
<source path="testui"/> <!-- this is where the entry point is in the test/src -->
</module>


The entry-point element references the Entry Point java class we wrote in the prior step. The source paths refer to the sub-packages with Java code that should be compiled in to JavaScript for our web page. The ‘inherits’ tag is analogous to a java import. com.google.gwt.user.User is a GWT Module that is leveraged by this Module. The ‘User’ Module must be imported in to every GWT Module. Other than what’s seen in this XML, there are a couple implicit elements not seen in the XML:




  • Because the ‘rename’ attribute was not specified for the ‘module’ element, the compiler assumes it should output the compiled JavaScript to a directory named com.gwtdesign.mvp.contactlist.ContactListTest in the web output directory. This is derived from the location and name of the Module file.


  • Because the ‘public’ element was not used, it is assumed that a directory named ‘public’ under the Module file will contain static resources for the web application.



Lastly, we need to define the HTML host file that will call the GWT-compiled JavaScript file. For our trivial test, it will look as follows:



<!DOCTYPE HTML> 
<html>
<head>
<meta http-equiv="content-type" content="text/html; charset=UTF-8">
<script type="text/javascript" language="javascript" src="com.gwtdesign.mvp.contactlist.ContactListTest.nocache.js">
</script>

</head>
<body>
<h1>Contact List Test Page</h1>
</body>
</html>


Looking at the full directory structure, you’ll see that the test code is isolated to the test/src folder while the production code is in the main src folder:



image



One interesting thing when looking at the source tree is that the UI logic is contained in src/com.gwtdesign.mvp.contactlist.client yet the JUnits that test it are in a ‘test’ sub-package, test/src/com.gwtdesign.mvp.contactlist.test. This is non-standard. Typically, JUnits live in the same Java package as the Java code they test. I may find a better way to do this, but for now, this seemed like the best way to have the Entry Point and HTML host page live in the test/src. If I didn’t put the JUnits somewhere else, the <source path="client"/> in the Module file would cause the GWT-compiler to try compiling the JUnits in to JavaScript.



In Eclipse, we now can Run as... ‘Web Application’ and the page can be viewed:



image



After the Web Application starts, the ‘Development Mode’ window in Eclipse will look something like the following:



image



However, we did not put our HTML host page in the war directory, so the GWT Eclipse Plugin did not provide the appropriate URL for our test page. The URL we’ll use looks like: http://localhost:8888/com.gwtdesign.mvp.contactlist.ContactListTest/ContactListTest.html?gwt.codesvr=localhost:9997



And here is the beautiful page that we see when hitting the URL:



image



What we’ve just done is pretty cool!




  • From Eclipse, the Run As… Web Application did some magic and now we’re able to hit our web page. There is no big app server (e.g. JBoss, Weblogic, etc.) that we need to deploy to in order to run this type of test.


  • By launching the test using Debug As… Web Application, we can set a break point in any of our Java code and interactions with the web page will break in Java code as we would hope! Even though GWT compiled the Java in to JavaScript, GWT has still maintained the capability to debug the JavaScript as the Java code that we originally wrote.


  • We’ve built a test to render just one component of the Contact List application and we’ve rendered this single UI component in isolation. Not only have we rendered it in isolation, but it is all wired up to emit a ContactSelected event if the user clicks on one of the contacts. This demonstrates a few things about the design/implementation methodology:

    • Seeing this UI Component rendered in isolation with all its functionality demonstrates that this component is reusable in case we wanted to use it somewhere else. It’s clearly not coupled to the Contact Details UI Component.


    • A typical interactive web page is very complex, made up of many UI components. When a large web page is not behaving as expected, it may be quite useful to be able to render each component in isolation as a means to finding a hard-to-track down bug.





To quickly demonstrate that we can do something when a Contact is selected, I’ll tweak the Entry Point slightly by adding the following lines of code at the end:



		eventBus.addHandler(ContactSelectedEvent.TYPE, new ContactSelectedEvent.ContactSelectedEventHandler() {

public void handleEvent(ContactSelectedEvent contactSelectedEvent) {
Window.alert("Contact selected: " +
contactSelectedEvent.getSelectedContact().getFirstName());
}
});


And now we can click on ‘Jim’ and see the alert:



image



In this post, we saw how to build out our view implementation with core GWT Widgets and also learned how to manually test a UI Component in isolation.

No comments:

Post a Comment

Followers