While writing some tests for SWTBot, there was quite some code duplication that could be removed by using some simple test patterns. This is part of a series of articles about how test code could be written better. This example uses SWTBot as a driver to drive an Eclipse application used by ACME Corporation.

Here is a snippet of a Test Case that creates an account in ACME Corporation’s customer management system.

public void testCreatesAccount() throws Exception {
    bot.menu("Accounts").menu("New").click();
    // nice wizard
    bot.shell("Create a new account").activate();
    bot.textWithLabel("Name:").setText("Will Coyote");
    bot.textWithLabel("Email:").setText("will@coyote");
    bot.button("Next>").click();
    // yet another wizard
    bot.shell("Address Details").activate();
    bot.textWithLabel("Mailing Address:").setText("Will Coyote, middle of, nowhere");
    bot.button("Finish").click();

    assertThatAccountIsCreated("Will Cooyte", "will@coyote.com");
}

That’s a great start to begin writing tests. But there’s the problem: What happens if the test fails somewhere and the “Create a new account” or the “Address Details” window remains open ? This means that the rest of the tests fail or do not run at all. Not a problem, tearDown() to the rescue:

protected void tearDown() throws Exception {
    closeWindow("Create a new account");
    closeWindow("Address Details");
}

private void closeWindow(String windowTitle) throws Exception {
    try {
    bot.shell(windowTitle).close();
    } catch (WidgetNotFoundException e) {
        // do nothing if the window is not found
    }
}

Now we write a test that tests if you’re able to create two users with the same name.

public void testShouldNotCreateTwoAccountsWithTheSameName() throws Exception {
    bot.menu("Accounts").menu("New").click();
    // nice wizard
    bot.shell("Create a new account").activate();
    bot.textWithLabel("Name:").setText("Will Coyote");
    bot.textWithLabel("Email:").setText("will@coyote");
    bot.button("Next>").click();
    // yet another wizard
    bot.shell("Address Details").activate();
    bot.textWithLabel("Mailing Address:").setText("Will Coyote, middle of, nowhere");
    bot.button("Finish").click();

    assertThatAccountIsCreated("Will Cooyte", "will@coyote.com");

    bot.menu("Accounts").menu("New").click();
    // nice wizard
    bot.shell("Create a new account").activate();
    bot.textWithLabel("Name:").setText("Will Coyote");
    bot.textWithLabel("Email:").setText("will@coyote");
    bot.button("Next>").click();
    // yet another wizard
    bot.shell("Address Details").activate();
    bot.textWithLabel("Mailing Address:").setText("Will Coyote, middle of, nowhere");
    bot.button("Finish").click();

    assertThatAccountIsNotCreated("Will Cooyte", "will@coyote.com");
}

Duplication, not a big deal, some bit of refactoring and you get to this. This also reduces the number of places where you’ll need to fix the test, if the label on one of the screens change.

public void testCreatesAccount() throws Exception {
    createAccount("Will Coyote", "will@coyote", "Will Coyote, middle of, nowhere");
    assertThatAccountIsCreated("Will Cooyte", "will@coyote.com");
}

public void testShouldNotCreateTwoAccountsWithTheSameName() throws Exception {
    createAccount("Will Coyote", "will@coyote", "Will Coyote, middle of, nowhere");
    assertThatAccountIsCreated("Will Cooyte", "will@coyote.com");
    createAccount("Will Coyote", "will@coyote", "Will Coyote, middle of, nowhere");
    assertThatAccountIsNotCreated("Will Cooyte", "will@coyote.com");
}

private void createAccount(String name, String email, String snailMail) throws WidgetNotFoundException, TimeoutException {
    bot.menu("Accounts").menu("New").click();
    // nice wizard
    bot.shell("Create a new account").activate();
    bot.textWithLabel("Name:").setText(name);
    bot.textWithLabel("Email:").setText(email);
    bot.button("Next>").click();
    // yet another wizard
    bot.shell("Address Details").activate();
    bot.textWithLabel("Mailing Address:").setText(snailMail);
    bot.button("Finish").click();
}

In the next article, you’ll get to see how you can reuse code better by using Screen Objects