back to article Don't unit test GUIs

It can be dangerous to make sweeping "Don't" statements. In Patterns of Enterprise Application Architecture, agile guru Martin Fowler coined his now-infamous first law of distributed object design: Don't distribute your objects. This is good advice to an extent but is also an overly simplistic viewpoint. The reader is left to …

COMMENTS

This topic is closed for new posts.
  1. Dan Haywood

    Naked Objects is a framework that makes testing UIs easy

    This isn't an unbiased post because I'm very heavily involved in Naked Objects (http://www.nakedobjects.org), but if you are interested in how to test the business logic behind the UI then this becomes trivially easy when the UI itself is automatically generated from the domain objects (which is what NO is all about).

    We're currently reworking the JUnit-based testing framework that ships with Naked Objects, and will be released as a point release in the next month or so (it's currently in our incubator). But to give you a flavour, if one has an action on an object such as Customer#placeOrder which can't be invoked (ie would be greyed out in the UI), then one would write the test as:

    try {

    proxiedCust.placeOrder(product355, 3);

    fail("Should have thrown exception");

    } catch(DisabledImperativelyException e) {

    assertThat(e.getMessage(), equalTo("cannot invoke"));

    }

    String documentText = getInMemoryDocumentor().toString();

    assertThat(documentText, equalTo(

    "Because the 'Place Order' action is currently disabled (cannot invoke), it cannot be invoked.\n"));

    The framework uses a CG-lib proxy to interact with the underlying business object in the same way that the auto-generated UI would. If the placeOrder action is disabled, the proxy throws an exception.

    Just thought this might be of interest to you.

    Cheers

    Dan

  2. James Richardson

    Don't do end-to-end testing

    Yes - thats right - you can just leave that little bit at the end - your entire client interface to a 'little bit of visual inspection'.

    Good idea.

    Just because Swing is "so simple it doesn't need testing", doesn't mean that you shouldn't do it.

    Seeing as however whizzy your application architecture - the ONLY thing that people ever will see is the Swing Gui - leaving it to visual inspection seems rather rash.

    Mind you - generating a UI from domain objects doesn't sound so great either - i expect it looks _really good_.

    Whats wrong with just a normal unit test (a trivial example):

    @Test

    public void canAddTwoNumbers() {

    calculatorUI.inputWithNumberButtons("5");

    calculatorUI.clickAddButton();

    calculatorUI.inputWithNumberButtons("2");

    calculatorUI.clickEqualsButton();

    calculatorUI.displaysNumber("7");

    }

  3. Chris Rimmer

    Swing doesn't promote separation of GUI and logic?

    I don't understand the comment about Swing not promoting separation of GUI and logic. IIRC, separation of GUI and logic was one of the main design goals of Swing. Not only are there models for essentially every Swing component (which admittedly often belong to the UI domain), but there are some excellent tutorials on java.sun.com showing you how to use Swing in the way it was intended i.e. storing data in Java beans, and using PropertyChangeEvents to update the GUI. In my experience, it works extremely well.

    As a simple illustration, a few years ago I wrote an application which involved the user completing an on-screen form while talking to a customer on the telephone. It had a save button (which saved the details entered to be completed later) and a submit button (to begin processing the details). When the model fired a PropertyChangeEvent to say that the "valid" Boolean property had changed (which was done in response to updates of model fields), a PropertyChangeListener changed the enabled state of the 'submit' button accordingly.

    Having said that, I completely agree with the thrust of the article - test the underlying model, and just let the GUI be a way for a user to communicate with that model.

  4. Matt Stephens

    James: "little bit of visual inspection"

    Hi James,

    Visual inspection implies a lot - creation of test cases, regression testing, steps to recreate known issues/prove fixed, etc. It's a whole bunch of stuff that I didn't mention in the article because that isn't what the article is about.

    But I agree that the front-end should be tested, and tested extensively: just that given its nature, automated testing isn't necessarily the most effective way of doing it. Robots/automated UI testers don't spot visual errors in quite the same way that humans do.

    I disagree with your point that "the ONLY thing that people ever will see is the Swing Gui". The data that you see in lists, tables, plus any other application state, comes directly from the model, which should be heavily unit-tested......

  5. Matt Stephens

    re: Swing doesn't promote separation of GUI and logic?

    Chris,

    Yes, separation of GUI and logic was one of the theoretical design goals of Swing. In practice, people tend to put app logic directly in the event listeners, which end up as anonymous inner classes inside a class that extends JPanel (or whatever). I've seen it over and over at many different companies. The example code in the article is an example of how the logic creeps insidiously into the GUI code. It's so easy to add a quick validation check into the listener, until very quickly the whole app ends up that way.

    As for Swing models, much of the model code tends to be "plumbing" code, e.g. a custom TableModel can contain just as much mechanical stuff to do with responding to user actions and notifying the UI of changes, as business logic. Swing models are not true business domain models. You end up with a class that doesn't really know what it is (is it a Swing mechanism or a business class?), again difficult (though not impossible) to unit-test. Making sure the logic is separated into dedicated classes just makes this sort of thing easier.

This topic is closed for new posts.