Search code examples
javaunit-testingswingjmock

Unit testing a Swing component


I am writing a TotalCommander-like application. I have a separate component for file list, and a model for it. Model support listeners and issues a notification for events like CurrentDirChanged etc. in following manner:

private void fireCurrentDirectoryChanged(final IFile dir) {
    if (SwingUtilities.isEventDispatchThread())
        for (FileTableEventsListener listener : tableListeners)
            listener.currentDirectoryChanged(dir);
    else {
        SwingUtilities.invokeLater(new Runnable() {
            public void run() {
                for (FileTableEventsListener listener : tableListeners)
                    listener.currentDirectoryChanged(dir);
            }
        });
    }
}

I've written a simple test for this:

@Test
public void testEvents() throws IOException {
    IFile testDir = mockDirectoryStructure();
    final FileSystemEventsListener listener = 
                context.mock(FileSystemEventsListener.class);
    context.checking(new Expectations() {{
        oneOf(listener).currentDirectoryChanged(with(any(IFile.class)));
    }});

    FileTableModel model = new FileTableModel(testDir);
    model.switchToInnerDirectory(1);
}

This does not work, because there is no EventDispatchThread. Is there any way to unit test this inside the headless build?

unit-testing java swing jmock


Solution

  • Note, generally speaking unit testing on UI stuff is always difficult because you have to mock out a lot of stuff which is just not available.
    Therefore the main aim when developing applications (of any type) is always to try to separate UI stuff from the main application logic as much as possible. Having strong dependencies here, make unit testing really hard, a nightmare basically. This is usually leveraged by using patterns like a MVC kind of approach, where you mainly test your controller classes and your view classes do nothing than constructing the UI and delegating their actions and events to the controllers. This separates responsibilities and makes testing easier.

    Moreover you shouldn't necessarily test things which are provided by the framework already such as testing whether events are correctly fired. You should just test the logic you're writing by yourself.