I've only just started using Vaadin, and "Can I do TDD with Vaadin?" was my first consideration. I have found (so far anyway) that it is actually quite easy; though I do end up writing a lot of code.
The first thing I had to do was write a number of factory classes. This is so that I can inject mock UI objects into my classes. For example:
public class ButtonFactory { public Button create() { return new Button(); } public Button create(String caption) { return new Button(caption); } public Button create(String caption, Button.ClickListener listener) { return new Button(caption, listener); } }
I then created factories for the main UI components that I needed:
@ApplicationScoped public class SiteAdminButtonBarFactory implements Serializable { private static final long serialVersionUID = -462493589568567794L; private ButtonFactory buttonFactory = null; private HorizontalLayoutFactory horizontalLayoutFactory = null; public SiteAdminButtonBarFactory() {} @Inject public SiteAdminButtonBarFactory(HorizontalLayoutFactory horizontalLayoutFactory, ButtonFactory buttonFactory) { this.horizontalLayoutFactory = horizontalLayoutFactory; this.buttonFactory = buttonFactory; } public SiteAdminButtonBar create() { HorizontalLayout layout = horizontalLayoutFactory.create(); layout.addComponent(addButton()); layout.addComponent(removeButton()); layout.addComponent(editButton()); return new SiteAdminButtonBar(layout); } private Button addButton() { return buttonFactory.create("Add"); } private Button removeButton() { return buttonFactory.create("Remove"); } private Button editButton() { return buttonFactory.create("Edit"); } }
The associated test code is:
public class SiteAdminButtonBarFactoryTest { private HorizontalLayout horizontalLayout = null; private HorizontalLayoutFactory horizontalLayoutFactory = null; private Button addButton = null; private Button removeButton = null; private Button editButton = null; private ButtonFactory buttonFactory = null; private SiteAdminButtonBarFactory siteAdminButtonBarFactory = null; @Test public void shouldCreateAHorizontalLayout() throws Exception { givenWeHaveAFullyConfiguredSiteAdminButtonBarFactory(); SiteAdminButtonBar siteAdminButtonBar = siteAdminButtonBarFactory.create(); assertThat(siteAdminButtonBar, is(notNullValue())); verify(horizontalLayoutFactory).create(); } @Test public void shouldContainAnADDButton() throws Exception { givenWeHaveAFullyConfiguredSiteAdminButtonBarFactory(); siteAdminButtonBarFactory.create(); verify(buttonFactory).create("Remove"); verify(horizontalLayout).addComponent(removeButton); } @Test public void shouldContainARemoveButton() throws Exception { givenWeHaveAFullyConfiguredSiteAdminButtonBarFactory(); siteAdminButtonBarFactory.create(); verify(buttonFactory).create("Edit"); verify(horizontalLayout).addComponent(editButton); } @Test public void shouldContainAnEditButton() throws Exception { givenWeHaveAFullyConfiguredSiteAdminButtonBarFactory(); siteAdminButtonBarFactory.create(); verify(buttonFactory).create("Add"); verify(horizontalLayout).addComponent(addButton); } private void givenWeHaveAFullyConfiguredSiteAdminButtonBarFactory() { horizontalLayout = mock(HorizontalLayout.class); horizontalLayoutFactory = mock(HorizontalLayoutFactory.class); when(horizontalLayoutFactory.create()).thenReturn(horizontalLayout); addButton = mock(Button.class); removeButton = mock(Button.class); editButton = mock(Button.class); buttonFactory = mock(ButtonFactory.class); when(buttonFactory.create("Add")).thenReturn(addButton); when(buttonFactory.create("Remove")).thenReturn(removeButton); when(buttonFactory.create("Edit")).thenReturn(editButton); siteAdminButtonBarFactory = new SiteAdminButtonBarFactory(horizontalLayoutFactory, buttonFactory); } }
I'll admit that at first I had to write the code first and then the test until I figured out how to structure things. Also, I haven't yet got as far as TDDing the event listeners etc (you'll notice that the button have captions, but no action listeners). But I'm getting there!