如何使用Vaadin进行测试驱动开发?

时间:2011-09-22 20:54:37

标签: java gwt tdd vaadin

构建基于Vaadin的应用程序的最佳方法是什么,以便我可以使用TDD(测试驱动开发)来创建应用程序?换句话说,我不想编写需要服务器或浏览器(甚至那些模拟器)的测试,因为它们可能太脆弱,太慢或两者兼而有之。

问题Translating GWT MVP Pattern to Vaadin有点相关,因为我正在寻找用于使我的UI“逻辑”尽可能可测试的正确模式,但我不确定MVP是否会转换为Vaadin。

5 个答案:

答案 0 :(得分:3)

查看Model View Presenter模式,也称为“简陋的视图”。

如果正确完成,View是唯一无法测试的对象,并且由于它不包含任何逻辑,您根本无需费心去测试它。

答案 1 :(得分:2)

我刚刚开始使用Vaadin,“我可以用Vaadin做TDD吗?”是我的首要考虑因素。我发现(到目前为止)它实际上很容易;虽然我最终写了很多代码。

我要做的第一件事就是写一些工厂类。这样我就可以将模拟UI对象注入到我的类中。例如:

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);
    }
}

然后我为我需要的主要UI组件创建了工厂:

@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");
    }
}

相关的测试代码是:

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);
    }
}

我承认,起初我必须首先编写代码然后再进行测试,直到我弄清楚如何构造事物。此外,我还没有TDDing事件监听器等(你会注意到按钮有字幕,但没有动作监听器)。但我到了那里!

答案 2 :(得分:1)

一旦Vaadin成为基于UI的Web框架,您就可以选择基于验收测试的测试解决方案,例如Selenium。因此,您仍然可以在业务/模型层中使用与UI类完全隔离的测试驱动开发。

用户界面是你可以触摸的东西,你可以改变它,看到修改的那一刻,你可以实时接受行为,并用一些好的工具,自动化。

业务/模型是一个关键层,您需要改进API设计以便更好地理解和业务转换为代码。对于任何更改,您需要保持安全,不要违反您的规则 - 并且这样做,只需使用单元测试(TDD完全应用于此处,但不是强制性的)

答案 3 :(得分:1)

模型视图Presenter模式实际上是划分Vaadin应用程序的表示逻辑的好方法。它甚至是官方Advanced Vaadin Training课程的一部分。在Vaadin中实施MVP的Here is the example。但是,根据具体应用,可以使用各种版本的MVP。

理想的状态是可测试的演示者包含尽可能多的逻辑,并且视图尽可能地被动。对于实际视图的测试,最好使用Web测试从用户的角度进行测试。 Vaadin为此提供了一个特殊的工具 - Vaadin TestBench,它基于Selenium Webdriver并被修改为Vaadin Environment。 TestBench有some advantages平原硒,例如vaadin调整等待ajax动作和高级屏幕截图比较。这应该与某种Selenium Grid结合使用,例如SauceLabs,它提供了OS,Web浏览器及其版本的各种组合,可以在您的测试中使用。

请注意,Vaadin TestBench不是免费的,需要许可证或Vaadin pro subscription

答案 4 :(得分:0)

您可以使用karibu测试框架:https://github.com/mvysny/karibu-testing。它使您可以使用实际成熟的Vaadin组件来运行和测试您的应用程序,因此您不必使用MVP或自定义组件工厂即可构建用于测试的特殊UI。请参阅上面的链接,了解有关如何为您的应用编写和运行Vaadin单元测试的具体示例和教程。