/ Vaadin

Creating Extendable and Testable addons for Vaadin

Making distributable components for Vaadin has become really easy with the introduction of the new addon architecture in Vaadin 6. This means that making an addon and sharing it with the world is as easy as packaging it in a jar and uploading it to the Vaadin directory. There are also tools available to help you on the way, If you're working in Eclipse there exists the Vaadin plugin which helps you with a lot of tasks like building the jar, compiling the widgetset etc. If you're not working in eclipse then ready made Ant build scripts exist which you can use for the same tasks.

When creating an addon you usually want its API to be easily used and understood, after all, most likely you are not designing the addon for yourself but for others to use in their projects. This means that in addition to the API being understandable and well documented the addon should also be easily extandable and be 90-100% unit tested. At least that is my goal.

So how do you go about creating such an addon. Well, I'll try to describe one way of doing it in this blog post, a way I have found effective. Of course if you have any improvement suggestions they are very much welcomed.

Overall addon architecture

Lets start by looking at the overall architecture of the addon, how could we split up the addon so it is both easily extendable and testable.

Vaadin Addon Architecture

In the figure above I have divided the addon in three layers.

The first layer represents the GWT or client side implementation of the component. Basically this layer represents a standalone GWT component which can be extracted and used in any GWT project. This will have as little as possible dependencies to Vaadin. If we are porting an existing GWT component to Vaadin then this would be that existing component.

The second layer is the communiction layer. This layer is also located at the client side and is the glue that ties together the GWT component with the server side component.

Finally, we have the server side implementation. This is the Addon API which other Vaadin developers use in the application to tie your component to their application.

To make a fully testable and extendable addon component, each of these layers will have to be easily extendable and testable by them selves with unit tests. The easiest way to achieve this is to separate each of the layers into their own class with its own API. This way other developers can easily choose to extend your component by only extending one of the layers. Also, layer specific unit tests can be written which makes it easier to identify possible bugs.

SpinButton - An example

![Spin Button](/content/images/2015/09/vaadin-6-addons-2.png)

To better understand the architecture I propose I've made a small example component which acts a numeric field. It allows the user to both enter the value by hand or increase or decrease the value by using the right hand side buttons. To keep the sources short and easily readable I have only tested it on Firefox, most likely it might look a little bit different on other browsers and would need some CSS tweaking but I will leave that as an exercise.

Project file hierarchy

Lets start by looking at the project structure first.

![](/content/images/2015/09/vaadin-6-addons-3.png)

The first thing you will notice is that the source code has been divided into three source folders src, test and demo folders. This separates our code nicely and keeps the packages well organized and easy to search in. Also by separating the addon sources from the test and demo application sources it will be easier to build the addon and only include the addon specific classes.

Now if we look at the src package it has basically been divided into three sub-packages.

In the root package (fi.jasoft.spinbutton) we have everything related to the server side. Here is the component API which developers will use in their application to incorporate your component. Here also is located the widgetset-specification xml which will tell the GWT compiler about our component. This is the Server layer abstraction.

Inside the root package we have the client subpackage (fi.jasoft.spinbutton.client.ui) which will contain the communication classes or "glue" which binds the GWT components with the server side Vaadin components. All these components are on the client side and will be compiled with the GWT compiler. These classes starts with a 'V' to denote they are Vaadin communication or "glue" classes. This is the Communication layer abstraction.

Inside the client package we have the gwt subpackage (fi.jasoft.spinbutton.client.ui.gwt) which will contain the actual client side implementation of the our component. These components will communicate with the Vaadin components on the server side via the communication layer. These components should have minimal dependencies to Vaadin so they easily can form composites with other GWT components or even be extracted to pure GWT applications. All classes in this package start with GWT to denote they are pure GWT components. This is the GWT layer abstraction.

Next, lets look at the test source folder. The first thing you will notice is that it has the exact same package structure as the src folder. By doing it this way we will know immediately by looking at the package structure if the test is a server side JUnit test or if it is a GWT unit test. So, if you did not already guess, in fi.jasoft.spinbutton is one JUnit test and the rest are all GWT tests.

If we look closer at the client sub-packages we see that there is one test class for the GWT layer which will test the GWTSpinButton class. The naming convention is the same here, all tests are prefixed by "GWT" to signify they are testing pure GWT components.

In the parent package we see one test class for the Communication layer, VSpinButtonTest which obviously will test the VSpinButton class. Also here the naming convention is the same, all tests which tests the communication layer are prefixed with a 'V'.

Finally we can see a single class which might seem out of place in the client package. All our client side test classes will extend this class and what it basically does is define some parameters for the GWT test runner so it can run our tests successfully. We'll look at that class later on.

And last but not least we have the demo source folder. It only contains the demo application which showcases our component and hopefully convinces everyone of our amazing skills. The package structure of this basically depends on your demo application so I'll leave that open.

The client side implementation

So, lets start looking at some code. We begin building our component by building and testing our client side implementation. As mentioned earlier this component should depend as little as possible on Vaadin and it should be easy to just take this component and use it in a pure GWT application. Here are the sources for the GWTSpinButton (GWTSpinButton.java):

package fi.jasoft.spinbutton.client.ui.gwt;  
import com.google.gwt.dom.client.Style.Float;  
import com.google.gwt.dom.client.Style.Unit;  
import com.google.gwt.event.dom.client.ClickEvent;  
import com.google.gwt.event.dom.client.ClickHandler;  
import com.google.gwt.event.logical.shared.HasValueChangeHandlers;  
import com.google.gwt.event.logical.shared.ValueChangeEvent;  
import com.google.gwt.event.logical.shared.ValueChangeHandler;  
import com.google.gwt.event.shared.HandlerRegistration;  
import com.google.gwt.user.client.ui.Button;  
import com.google.gwt.user.client.ui.Composite;  
import com.google.gwt.user.client.ui.FlowPanel;  
import com.google.gwt.user.client.ui.TextBox;  
import com.google.gwt.user.client.ui.ValueBoxBase.TextAlignment;  

/** 
 * A simple Spin Button widget to enter numerical input. 
 *  
 * @author John Ahlroos (www.jasoft.fi) 
 */  
public class GWTSpinButton extends Composite implements HasValueChangeHandlers<Integer> {  

    // The text box which holds the value  
    private final TextBox textbox = new TextBox();  

    // The increase value button  
    private final Button buttonUp = new Button("+", new ClickHandler() {  
        public void onClick(ClickEvent event) {  
            increaseValue();  
        }  
    });  

    // The decrease value button  
    private final Button buttonDown = new Button("-", new ClickHandler() {  
        public void onClick(ClickEvent event) {  
            decreaseValue();  
        }  
    });  

    // The panel that holds the textfield and buttons  
    private final FlowPanel root = new FlowPanel();  

    // The current value of the spin button  
    private int value;  

    /** 
     * Default constructor 
     */  
    public GWTSpinButton(){  
        this(0);  
    }  

    /** 
     * Constructor with value 
     *  
     * @param value 
     *      The initial value of the spin box 
     */  
    public GWTSpinButton(int value){  
        this.value = value;  

        // Add widgets  
        textbox.setValue(String.valueOf(value));  
        textbox.setPixelSize(50, 28);  
        textbox.setAlignment(TextAlignment.RIGHT);  
        textbox.getElement().getStyle().setFloat(Float.LEFT);  
        textbox.getElement().getStyle().setFontSize(28, Unit.PX);  
        textbox.addValueChangeHandler(new ValueChangeHandler<String>() {  
            public void onValueChange(ValueChangeEvent<String> event) {  
                try{  
                    GWTSpinButton.this.value = Integer.parseInt(event.getValue());  
                    ValueChangeEvent.fire(GWTSpinButton.this, GWTSpinButton.this.value);  
                    textbox.setValue(String.valueOf(GWTSpinButton.this.value), false);  
                } catch(NumberFormatException nfe){  
                    // Reset textbox if value is invalid  
                    textbox.setValue(String.valueOf(GWTSpinButton.this.value), false);  
                }  
            }  
        });  
        root.add(textbox);  

        buttonUp.setWidth("18px");  
        buttonUp.setHeight("18px");  
        buttonUp.getElement().getStyle().setFloat(Float.RIGHT);  
        root.add(buttonUp);  

        buttonDown.setWidth("18px");  
        buttonDown.setHeight("18px");  
        buttonDown.getElement().getStyle().setProperty("clear", "right");  
        buttonDown.getElement().getStyle().setFloat(Float.RIGHT);  
        root.add(buttonDown);  

        root.setStyleName("gwt-spinbutton");  
        initWidget(root);  
    }  

    /** 
     * Increases the value by +1 
     */  
    public void increaseValue(){  
        setValue(getValue()+1);  
    }  

    /** 
     * Decrease the value by -1 
     */  
    public void decreaseValue(){  
        setValue(getValue()-1);  
    }  

    /** 
     * Returns the value of the spin button 
     *  
     * @return 
     *      Returns the current value 
     */  
    public int getValue(){  
        return this.value;  
    }  

    /** 
     * Sets the value 
     *  
     * @param value 
     *      The value of the spin button 
     */  
    public void setValue(int value){  
        this.value = value;  
        textbox.setValue(Integer.toString(value));  
        ValueChangeEvent.fire(this, this.value);  
    }  

    /* 
     * (non-Javadoc) 
     * @see com.google.gwt.event.logical.shared.HasValueChangeHandlers# 
     * addValueChangeHandler(com.google.gwt.event.logical.shared.ValueChangeHandler) 
     */  
    public HandlerRegistration addValueChangeHandler(  
            ValueChangeHandler<Integer> handler) {  
        return addHandler(handler, ValueChangeEvent.getType());  
    }  
}  

As you can see it is a pretty simple component. It is a composite widget with a textfield for displaying the value and two buttons for increasing or decreasing the value. The value changes can be listened to via the HasValueChangeHandlers interface. The value can also be set or retrieved in code by using the value setter and getter as well as increased and decreased by using public methods. Nothing much to it.

One thing you might notice is that I've split out the code to increase or decrease the value into their own methods from the ClickHandlers at lines 29 and 36. By separating the logic from the UI in this way it will be easier to test the logic without needing to abuse the UI methods.

Actually I should have shown you the unit test class first in true TDD fashion, but I usually work simultaneously on both classes while I develop since i find the API changing rather often. So here is now the the corresponding unit test class GWTSpinButtonTest.java which tests our GWT component.

package fi.jasoft.spinbutton.client.ui.gwt;  
import org.junit.Test;  
import com.google.gwt.event.logical.shared.ValueChangeEvent;  
import com.google.gwt.event.logical.shared.ValueChangeHandler;  
import fi.jasoft.spinbutton.client.SpinButtonGWTTestCase;  

public class GWTSpinButtonTest extends SpinButtonGWTTestCase {  

    @Test  
    public void testConstructorAndGetValue(){  
        // Test default constructor  
        GWTSpinButton btn = new GWTSpinButton();  
        assertEquals(0, btn.getValue());  

        // Test positive values  
        btn = new GWTSpinButton(123);  
        assertEquals(123, btn.getValue());  

        // Test negative values  
        btn = new GWTSpinButton(-123);  
        assertEquals(-123, btn.getValue());  
    }  

    @Test  
    public void testGetAndSetValue(){  

        GWTSpinButton btn = new GWTSpinButton();  

        // Test positive values  
        btn.setValue(4321);  
        assertEquals(4321, btn.getValue());  

        // Test negative values  
        btn.setValue(-4321);  
        assertEquals(-4321, btn.getValue());  
    }  

    @Test  
    public void testIncreasingValue(){  
        GWTSpinButton btn = new GWTSpinButton(0);  
        btn.increaseValue();  
        assertEquals(1, btn.getValue());  
    }  

    @Test  
    public void testDecreasingValue(){  
        GWTSpinButton btn = new GWTSpinButton(0);  
        btn.decreaseValue();  
        assertEquals(-1, btn.getValue());  
    }  

    // Helper variables for testValueChangeEvent() test  
    private boolean valueChangeEventOccured  = false;  
    private int valueChangeEventValue = 0;  

    @Test  
    public void testValueChangeEvent(){  
        GWTSpinButton btn = new GWTSpinButton(0);  
        btn.addValueChangeHandler(new ValueChangeHandler<Integer>() {  
            public void onValueChange(ValueChangeEvent<Integer> event) {  
                valueChangeEventOccured = true;  
                valueChangeEventValue = event.getValue();  
            }  
        });  

        valueChangeEventOccured = false;  
        btn.setValue(100);  
        assertTrue(valueChangeEventOccured);  
        assertEquals(100, valueChangeEventValue);  

        valueChangeEventOccured = false;  
        btn.increaseValue();  
        assertTrue(valueChangeEventOccured);  
        assertEquals(101, valueChangeEventValue);  

        valueChangeEventOccured = false;  
        btn.decreaseValue();  
        assertTrue(valueChangeEventOccured);  
        assertEquals(100, valueChangeEventValue);  
    }  
}  

As you can see it is pretty much a standard JUnit test which tests most of the functionality of our GWTSpinButton component. It is by no means complete, but it does most of the things.

There is however one thing that is different from an ordinary JUnit test. The test class extends SpinButtonGWTTestCase. What is this class? Let me show you how SpinButtonGWTTestCase.java looks like:

package fi.jasoft.spinbutton.client;  
import com.google.gwt.junit.client.GWTTestCase;  

public class SpinButtonGWTTestCase extends GWTTestCase {  

    private static final String WIDGETSET = "fi.jasoft.spinbutton.SpinButtonWidgetset";  

    public String getModuleName() {  
        return WIDGETSET;  
    }  
}  

The first thing you notice is that it extends GWTTestCase. This is GWT's equivalent of JUnit's TestCase class and it functions in basically the same way. It has the standard setUp() and tearDown() methods (even though they are called gwtSetUp() and gwtTearDown()) and you define test cases with the "test" prefixes in your function name.

However, the GWTTestCase needs you to implement the getModuleName() method which will tell the test runner where it can find the module definition. In Vaadin this is called the widgetset and as you can see I am returning the path to it in my implementation above. I have found that extracting this into it's own class which I extend in each test case is easier than to manually specify these in each test case.

That pretty much takes care of our client side implementation and testing. You can now use our component in any GWT project you have.

The vaadin client-server glue implementation

But we are not striving for any GWT project, we want to make our widget a certified Vaadin component. To do that we need to hook it up to the Vaadin client side framework.

I call this the glue that holds together the GWT component and the Vaadin server side component. If you look at many existing Vaadin components you will notice that this glue is intertwined with the client side implementation of the component. This is in my opinion a very bad practice. Not only are you making your components fully dependent on Vaadin but it also usually makes the client side implementation really hard to extend and test. So, I propose that instead of mixing this glue into the implementation itself, you should separate it into its own class which uses the implementations public API instead. This not only makes the client side implementation portable, it also forces you to make a clear API for the client side implementation.

As I mentioned before, all these "glue" files are prefixed with a "V" to denote that they are glue files. Lets take a look at the SpinButton glue file (VSpinButton.java):

package fi.jasoft.spinbutton.client.ui;  
import com.vaadin.terminal.gwt.client.ApplicationConnection;  
import com.vaadin.terminal.gwt.client.Paintable;  
import com.vaadin.terminal.gwt.client.UIDL;  
import com.google.gwt.event.logical.shared.ValueChangeEvent;  
import com.google.gwt.event.logical.shared.ValueChangeHandler;  
import com.google.gwt.event.shared.HandlerRegistration;  
import fi.jasoft.spinbutton.SpinButton;  
import fi.jasoft.spinbutton.client.ui.gwt.GWTSpinButton;  

/** 
 * A class for handling the communication between the client implementation  
 * {@link GWTSpinButton} and the server side implementation {@link SpinButton} 
 * @author John Ahlroos (www.jasoft.fi) 
 */  
public class VSpinButton extends GWTSpinButton implements Paintable, ValueChangeHandler<Integer> {  

    public static final String VALUE_VARIABLE = "value";  

    // Some Vaadin specific references needed in communication  
    protected String paintableId;  
    protected ApplicationConnection client;  

    // Registration for the ValueChangeEvent handler  
    private HandlerRegistration valueChangeHandlerRegistration;  

    /** 
     * Default constructor 
     */  
    public VSpinButton() {  
        super();  
        // Listen to value change events  
        valueChangeHandlerRegistration = addValueChangeHandler(this);  
    }  

    /** 
     * Called whenever an update is received from the server  
     */  
    public void updateFromUIDL(UIDL uidl, ApplicationConnection client) {  
        // Ensure the update is meant for me  
        if (client.updateComponent(this, uidl, true)) {  
            return;  
        }  
        // Save for later  
        this.client = client;  
        paintableId = uidl.getId();  
        // Handle value changes on the server side  
        if(uidl.hasVariable(VALUE_VARIABLE)){  
            handleChangedValue(uidl.getIntVariable(VALUE_VARIABLE));  
        }  
    }  

    /** 
     * Handles a changed value received from the server 
     *  
     * @param value 
     *      The value received from the server 
     */  
    protected void handleChangedValue(int value){  
         //Set the value recieved from the server but do not trigger a new value change event   
        valueChangeHandlerRegistration.removeHandler();  
        setValue(value);  
        valueChangeHandlerRegistration = addValueChangeHandler(this);  
    }  

    /* 
     * (non-Javadoc) 
     * @see com.google.gwt.event.logical.shared.ValueChangeHandler 
     *      #onValueChange(com.google.gwt.event.logical.shared.ValueChangeEvent) 
     */  
    public void onValueChange(ValueChangeEvent<Integer> event) {  
        // Communicate the new value to the server  
         client.updateVariable(paintableId, VALUE_VARIABLE, event.getValue(), true);  
    }  
}  

How do we hook up our widget to Vaadin? That is easy. We extend the real GWT component and implement the Paintable interface. That is it, our widget is now recognized by the Vaadin framework. The thing we now need to do is handle the interaction between the Vaadin server side component and the GWT widget. Since our GWT component has a clear API it shouldn't be too hard.

I am not going to go too deep into the Vaadin communication mechanism, the only thing you need to know is that when you receive data from the server then the updateFromUIDL method is called with the data, and when you want to send data to the server you call the ApplicationConnection.updateVariable method with the data you want to send.

Each variable you send and receive has a name, in the case of the SpinButton only one variable is used, the "value" variable which contains the value.

If you look at the updateFromUIDL -method you will see that I check if the value variable is present and if it is I pass it along to the protected handleChangedValue -method. Again I have split out the handling logic from the event logic into its own method so implementing a different behavior could be done by extension.

To pass client side value changes to the server I have attached a valueChangeHandler to the GWTSpinButton and implemented the necessary interface. When a value change occurs I send the value directly to the server side Vaadin implementation. Again, since the GWT component has clear API this was really easy to do.

But the implementation would not be complete without unit tests, so here is the corresponding unit test class for the "glue" file (VSpinButtonTest.java):

package fi.jasoft.spinbutton.client.ui;  
import org.junit.Test;  
import com.google.gwt.user.client.ui.Widget;  
import com.vaadin.terminal.gwt.client.ApplicationConnection;  
import com.vaadin.terminal.gwt.client.UIDL;  
import fi.jasoft.spinbutton.SpinButton;  
import fi.jasoft.spinbutton.client.SpinButtonGWTTestCase;  
import fi.jasoft.spinbutton.client.ui.gwt.GWTSpinButton;  

/** 
 * A test class for testing the server-client communication  
 * between {@link GWTSpinButton} and {@link SpinButton} 
 */  
public class VSpinButtonTest extends SpinButtonGWTTestCase {  

    /** 
     * A mock class to simulate a {@link ApplicationConnection} and to keep 
     * the last value sent to the server 
     */  
    private static class MockApplicationConnection extends ApplicationConnection{  
        private int lastValue = 0;  
        @Override  
        public boolean updateComponent(Widget component, UIDL uidl,  
                boolean manageCaption) {  
            return false;  
        }  
        @Override  
        public void updateVariable(String paintableId, String variableName,  
                int newValue, boolean immediate) {  
            if(immediate && variableName.equals(VSpinButton.VALUE_VARIABLE)){  
                lastValue = newValue;  
            }  
        }  
        public int getLastValue(){  
            return lastValue;  
        }  
    }  

    /** 
     * Test for testing server value updates 
     */  
    @Test  
    public void testServerUpdatedValue(){  
        VSpinButton btn = new VSpinButton();  
        // Trigger server response with value variable  
        btn.updateFromUIDL(simulateValueChangeUIDL(100), new MockApplicationConnection());  
        assertEquals(100, btn.getValue());  
    }  

    /** 
     * Test for testing client side value updates 
     */  
    @Test  
    public void testClientUpdatedValue(){  
        VSpinButton btn = new VSpinButton();  
        MockApplicationConnection client = new MockApplicationConnection();  

        // Notify button of application connection, by calling updateFromUIDL once  
        btn.updateFromUIDL(simulateValueChangeUIDL(100), client);  

        //Trigger a value change event on the client side  
        btn.setValue(10);  

        /* The SpinButton should have called ApplicationConnection.updateVariable  
         * with the new value and the immediate flag set to true. 
         */  
        assertEquals(10, client.getLastValue());  
    }  

    /** 
     * Returns a UIDL with the value variable set to the value 
     * @param value The value of the SpinButton 
     * @return An UIDL with the value variable set 
     */  
    private static native UIDL simulateValueChangeUIDL(int value)  
    /*-{ 
        var obj = new Array(); 
        obj[1] = new Array(); 
        obj[1]["v"] = new Array(); 
        obj[1]["v"]["value"] = value; 
        return obj; 
    }-*/;  
}  

Nothing really new there, since the glue class is on the client side we need to extend our SpinButtonGWTTest class to get the correct module information. Then we just do some tests on those communication classes by using a mock ApplicationConnection class and simulated UIDLs. This is again not a complete test but it tests the basics at least.

We are now finished with the client side, lets see how we can bring all this together on the server side.

The server side implementation

Here is the implementation (SpinButton.java):

package fi.jasoft.spinbutton;  
import java.util.Map;  
import com.vaadin.terminal.PaintException;  
import com.vaadin.terminal.PaintTarget;  
import com.vaadin.ui.AbstractField;  
import fi.jasoft.spinbutton.client.ui.VSpinButton;  

/** 
 * Server side component for the VSpinButton widget. 
 */  
@com.vaadin.ui.ClientWidget(fi.jasoft.spinbutton.client.ui.VSpinButton.class)  
public class SpinButton extends AbstractField {  

    public SpinButton() {  
        // By default the value is 0  
        setInternalValue(0);  
    }  

    /* 
     * (non-Javadoc) 
     * @see com.vaadin.ui.AbstractField#paintContent(com.vaadin.terminal.PaintTarget) 
     */  
    @Override  
    public void paintContent(PaintTarget target) throws PaintException {  
        super.paintContent(target);  
        target.addVariable(this, VSpinButton.VALUE_VARIABLE, (Integer)getValue());  
    }  

    /* 
     * (non-Javadoc) 
     * @see com.vaadin.ui.AbstractField#changeVariables(java.lang.Object, java.util.Map) 
     */  
    @Override  
    public void changeVariables(Object source, Map<String, Object> variables) {  
        super.changeVariables(source, variables);  
        if(variables.containsKey(VSpinButton.VALUE_VARIABLE)){  
            int newValue = (Integer)variables.get(VSpinButton.VALUE_VARIABLE);  
            if(newValue != (Integer)getValue()){  
                setValue(newValue, true);  
            }  
        }  
    }  

    /* 
     * (non-Javadoc) 
     * @see com.vaadin.ui.AbstractField#getType() 
     */  
    @Override  
    public Class<?> getType() {  
        return Integer.class;  
    }  
}  

That is 52 lines of code, so there is not much to look at.

The important thing is the ClientWidget annotation which binds this server side implementation with the "glue" on the client side. This tells Vaadin that the updates sent from this component should be sent to that glue class on the client side. Simple as that.

The SpinButton extends the AbstractField which basically means the this component is a field with a value and you can attach validators and such to it. I've also overriden two methods; paintContent and changeVariables. These are responsible for sending and receiving data to and from the client side glue (remember updateFromUIDL and ApplicationConnection.updateVariable?).

The paintContent-method is called when the component is "painted", i.e. data is sent to the client side. Here we add the value variable to the target which later is received by updateFromUIDL.

The changeVariables-method is called when the client has sent some data to the server. Here we read the value variable and if it has changed then set the value on the server side.

Finally, we have the overriden getType-method. It tells Vaadin what kind of field it is, in our case only integer values can be handled by the field so we return the Integer class.

Of course we want to test the server side implementation as well with unit tests so here is one for the SpinButton class (SpinButtonTest.java):

package fi.jasoft.spinbutton;  
import static org.junit.Assert.*;  
import java.util.Map;  
import org.junit.Test;  
import com.google.gwt.dev.util.collect.HashMap;  
import com.vaadin.terminal.PaintException;  
import com.vaadin.terminal.PaintTarget;  
import com.vaadin.terminal.Paintable;  
import com.vaadin.terminal.Resource;  
import com.vaadin.terminal.StreamVariable;  
import com.vaadin.terminal.VariableOwner;  
import fi.jasoft.spinbutton.client.ui.VSpinButton;  

public class SpinButtonTest {  

    private class MockPaintTarget implements PaintTarget{  
        private int lastValuePainted = 0;  

        public void addSection(String sectionTagName, String sectionData) throws PaintException { }  
        public boolean startTag(Paintable paintable, String tag) throws PaintException { return false; }  
        public void paintReference(Paintable paintable, String referenceName) throws PaintException { }  
        public void startTag(String tagName) throws PaintException { }  
        public void endTag(String tagName) throws PaintException { }  
        public void addAttribute(String name, boolean value) throws PaintException { }  
        public void addAttribute(String name, int value) throws PaintException { }  
        public void addAttribute(String name, Resource value) throws PaintException { }  
        public void addVariable(VariableOwner owner, String name,StreamVariable value) throws PaintException { }  
        public void addAttribute(String name, long value) throws PaintException {}  
        public void addAttribute(String name, float value) throws PaintException { }  
        public void addAttribute(String name, double value) throws PaintException { }  
        public void addAttribute(String name, String value) throws PaintException { }  
        public void addAttribute(String name, Map<?, ?> value) throws PaintException { }  
        public void addAttribute(String name, Paintable value) throws PaintException { }  
        public void addVariable(VariableOwner owner, String name, String value) throws PaintException { }  
        public void addVariable(VariableOwner owner, String name, long value) throws PaintException {}  
        public void addVariable(VariableOwner owner, String name, float value) throws PaintException { }  
        public void addVariable(VariableOwner owner, String name, double value) throws PaintException { }  
        public void addVariable(VariableOwner owner, String name, boolean value) throws PaintException { }  
        public void addVariable(VariableOwner owner, String name, String[] value) throws PaintException { }  
        public void addVariable(VariableOwner owner, String name, Paintable value) throws PaintException { }  
        public void addUploadStreamVariable(VariableOwner owner, String name) throws PaintException { }  
        public void addXMLSection(String sectionTagName, String sectionData, String namespace) throws PaintException { }  
        public void addUIDL(String uidl) throws PaintException { }  
        public void addText(String text) throws PaintException { }  
        public void addCharacterData(String text) throws PaintException {}   
        public void addAttribute(String string, Object[] keys) { }  
        public String getTag(Paintable paintable) { return null; }  
        public void addVariable(VariableOwner owner, String name, int value) throws PaintException {   
            if(name.equals(VSpinButton.VALUE_VARIABLE)){  
                lastValuePainted = value;  
            }  
        }  
        public int getLastValuePainted(){  
            return lastValuePainted;  
        }  
    }  

    @Test  
    public void testType() {  
        SpinButton btn = new SpinButton();  
        assertEquals(Integer.class, btn.getType());  
    }  

    @Test  
    public void testPaintValue() {  
        MockPaintTarget target = new MockPaintTarget();  
        SpinButton btn = new SpinButton();  
        btn.setValue(123);  
        try {  
            btn.paintContent(target);  
        } catch (PaintException e) {  
            e.printStackTrace();  
        }  
        assertEquals(123, target.getLastValuePainted());  
    }  

    @Test  
    public void testRecieveValue() {  
        Map<String, Object> variables = new HashMap<String, Object>();  
        variables.put(VSpinButton.VALUE_VARIABLE, 123);  

        SpinButton btn = new SpinButton();  

        // Simulate changing value on the client side  
        btn.changeVariables(btn, variables);  

        assertEquals(123, btn.getValue());  
    }  
}  

It's a basic JUnit test class which tests most of the things our SpinButton can do on the server side. Nothing special here.
Automatic testing

Of course we could run each of these test individually, either by invoking the GWT test runner for the client side tests or JUnit for the server side tests. But that is not very efficient and if you are for instance using a CI system like Jenkins you probably want to automate the whole process. Making an ant-script to run these tests automatically is really easy and I am going to show you how.

Start by creating an ant script called test.xml in the root folder of the project. Then lets add some build targets to that script.

Properties

First we define some basic properties for the targets.

<!-- Basic build properties -->  
<property name="src.dir" value="src" />  
<property name="test.dir" value="test" />  
<property name="test.classes.dir" value="build/test/classes" />  
<property name="gwt.test.output.dir" value="build/test/gwt" />  
<property name="lib" value="WebContent/WEB-INF/lib" />  

<!-- Classpath needed for JUnit -->  
<path id="test.classpath">  
    <pathelement path="${test.classes.dir}" />  
    <pathelement path="${src.dir}" />  
    <pathelement path="${test.dir}" />  
    <fileset dir="${lib}">  
        <include name="**/*.jar"/>  
     </fileset>  
</path>  
Build the sources

Then we will need to build the sources

<!-- Cleans up testing directories -->  
<target name="tests-clean">  
    <delete dir="${test.classes.dir}" />  
    <delete dir="${gwt.test.output.dir}" />  
</target>  

<!-- Compile all classes for unit tests -->  
<target name="compile-classes" depends="tests-clean">  
    <mkdir dir="${test.classes.dir}" />  
    <javac srcdir="${src.dir};${test.dir}" destdir="${test.classes.dir}" >  
        <classpath refid="test.classpath" />  
    </javac>  
</target>  
Target for running the server side tests

Then we add a target for running the server side tests

<!-- Server side JUnit tests -->  
<target name="serverside-tests" depends="compile-classes">  
    <junit fork="yes" haltonfailure="yes">  
            <classpath refid="test.classpath" />  
            <formatter type="plain" usefile="false" />  
            <batchtest>  
                <fileset dir="${test.classes.dir}">  
                    <include name="**/**Test.class" />  
                    <exclude name="**/client/**" />  
                </fileset>  
            </batchtest>  
     </junit>  
</target>  
Target for running the client side tests

And finally a target for running the client side tests

<!-- GWT Unit tests for the client side -->  
<target name="clientside-tests" depends="compile-classes">  
    <mkdir dir="${gwt.test.output.dir}" />  
    <junit fork="yes" haltonfailure="yes" printSummary="yes">  
        <jvmarg value="-Dgwt.args=-out ${gwt.test.output.dir}" />  
        <formatter type="plain" usefile="false" />  
        <classpath refid="test.classpath" />  
         <batchtest>  
                <fileset dir="${test.classes.dir}">  
                    <include name="**/client/**/**Test.class" />  
                </fileset>  
            </batchtest>  
    </junit>  
</target>  

And that is it. We can now run only the server side tests or the client side tests or of course both to check nothing is broken.

Summary

I've now shown you one way of creating addons that are both easily extendable on both the server and client side as well as shown you it is fully possible to create unit tests for most of your addon code. The core Vaadin framework does not currently adhere to this approach which most of us who has tried to use or extend the functionality of the client side implementation are painfully aware of. My hope is this will change in the future.

I've heard many tell me that unit testing the client side is not needed or too difficult but as I have demonstrated it does not need to be that way. You just have to put as much of an effort on the client side API as you do on the server side. This should be obvious but in too many projects the client side code is considered a second class citizen when it really shouldn't be since many bugs are usually found here!

It is however true that browser differences cannot be tested using only unit tests. To ensure the look and feel of the component cross browser you will need to use a framework like Selenium or Vaadin Testbench to ensure your components looks and behaves the same in each browser. But as long as you separate the logic from the UI then unit tests will help you a long way.

All the sources and project can be downloaded as a zip archive here.

A ready made SpinButton addon can which you can drop in any Vaadin project can be downloaded here.

That said, I hope you find this article useful and see you on the Vaadin forums ;)