User Tools

Site Tools



This shows you the differences between two versions of the page.

Link to this comparison view

Both sides previous revision Previous revision
blog:swt_graphical_unit_tests_are_easy [2008/06/06 11:44]
djo Discussion status changed
blog:swt_graphical_unit_tests_are_easy [2014/10/17 22:08] (current)
Line 1: Line 1:
 +====== SWT graphical unit tests are easy :-) ======
 +11 December, 2007
 +I can't believe how long it's been since I've posted! Wow. Guess time flies when you're having fun, which I've been having a lot of lately. My new contract is to help make RCP the de facto standard graphical interface platform worldwide at a major Fortune 500 firm...
 +But on to the good stuff... :-)
 +Yesterday, Doug Schaefer [[http://​​2007/​12/​agr-is-dead-apparently.html|wondered aloud]] how to unit test GUIs without some sort of robot. Short answer: with JUnit, like you've been doing all along, and a simple coding convention.
 +**First**, the coding convention:
 +    * Always, **always**, //​**always**//,​ create your user interface inside a Composite. Then you can instantiate your Composite inside a View, inside an Editor, or inside a Shell running inside a JUnit test.
 +**Second,** how to test it:
 +Create an abstract subclass of TestCase, say SWTTestCase.
 +<code java>
 +public class SWTTestCase extends TestCase {
 +    protected Display display = Display.getDefault();​
 +    protected Shell shell = null;
 +    ​
 +    protected void setUp() throws Exception {
 +        super.setUp();​
 +        newShell();
 +        methodCalls = new HashSet();
 +    }
 +    ​
 +    protected void tearDown() throws Exception {
 +        super.tearDown();​
 +        display.syncExec(new Runnable() {
 +            public void run() {
 +                disposeShell();​
 +            }
 +        });
 +    }
 +    ​
 +    protected void newShell() {
 +        disposeShell();​
 +        shell = new Shell(display,​ SWT.SHELL_TRIM);​
 +        shell.setLayout(new FillLayout());​
 +    }
 +    private void disposeShell() {
 +        if (shell != null) {
 +            shell.dispose();​
 +            shell = null;
 +        }
 +    }
 +Make your SWT graphical unit tests extend SWTTestCase. You will now have a shiny new Shell in your unit test at the beginning of each test method courtesy of the inherited #setUp() method.
 +If you followed **convention #1,** you can now instantiate your user interface inside this shell, poke data into it, fire events at it, and run asserts against it.
 +Here are some notes to get you started:
 +    * Since you have direct access to the controls in your Composite through its API, your unit tests are fully refactorable,​ unlike most robot-oriented test scripts.
 +    * There'​s nothing wrong with calling #setText() directly on controls rather than simulating typing, unless the thing you're testing depends on keystrokes being received one at a time. With this approach, you get the benefit of being able to intelligently use your controls'​ API to set up your tests rather than having to alwys poke at them from the UI.
 +    * Having said that, it's nice to have #​type(String),​ #​type(char),​ and #type(int swtKeyCode) methods. You don't need them often, but when you need them, you need them badly.
 +    * Similarly, variations on #​mouseClick(int button, ...) are useful.
 +Examples of this sort of unit test can be found in the JFace Data Binding test plug-ins. We're also using this style of GUI unit testing successfully at my client.
 +Areas where we've had trouble is in getting the various #type() methods right. Currently, some versions of #type() work but some don't, and this is a road less traveled in the SWT API, so help on Google and in the Eclipse newsgroup archives has not been easy to find. I would love to hear from someone who has successfully implemented all three versions of #type() listed above.
 +Lastly, I am not sure how to make this solution scale up to the level of integration tests. This is an interesting open question I'd love to hear from people about.