Testing a plain SWT Application with SWTBot

Revision History
18 April 2014 Modified the SWTBot test so that it can be reused also in a test suite (see the comments to this post).

I happened to give a lecture at the University of Florence on Test Driven Development; besides the standard Junit tests I wanted to show the students also some functional tests with SWTBot. However, I did not want to introduce Eclipse views or dialogs, I just wanted to test a plain SWT application with SWTBot.

In the beginning, it took me some time to understand how to do that (I had always used SWTBot in the context of an Eclipse application); thanks to Mickael Istria, who assisted me via Skype, it ended up being rather easy.

You can find this example here: https://github.com/LorenzoBettini/junit-swtbot-example.

The SWT application is a simple dialog that computes the factorial of the given input (nothing fancy, its code can be seen here).

swtbot-test-example1

If we now want to test this SWT application with SWTBot, we can write an abstract base class that we use for our tests (see also the online code)

And we use this base class in our tests, for instance

There are a few things to note in the abstract base class:

  • You need to spawn the application in a new thread (the bot will run in a different thread)
  • You must start the application before creating the bot (otherwise the Display will be null)
  • after that you can simply use SWTBot API as you’re used to.

Note that the thread will create our window and then it will enter the event loop; this thread synchronizes with the @Before method (executed before each test), which creates the SWTBot (using the shell created by the thread). The @After method (executed after each test), will close our window, so that each test is independent from each other. The thread executes in an infinite loop, thus as soon as the shell is closed it will create a new one, etc.

Of course, this must be executed as a “Junit test”, NOT as a “Plug-in Junit test”, neither as a “SWTBot Test”, since we do not want any Eclipse application while running the test:

swtbot-test-example2

In the sources of the example you can find also the files to run the tests headlessly with Buckminster or with Maven/Tycho. Just enter the directory mathutils.build and

for Buckminster or

for Maven.

For Buckminster, you just need to save the launch configuration you used to run the test, and use the junit command:

For Tycho, you must specify <packaging>eclipse-test-plugin</packaging>, but without further configuration. This will default useUIHarness to false.

During the headless run, first the Junit tests for the implementation of the factorial will be executed (these are not interesting in the context of SWTBot) and then the SWTBot tests will be executed.

 

 

Be Sociable, Share!

25 thoughts on “Testing a plain SWT Application with SWTBot

    1. Lorenzo Bettini Post author

      I always run my SWTBot tests from a test suite, without problems. Are you experiencing problems with test suites?

      Reply
  1. BR

    I’m running the test suite from Eclipse Juno and I’ve had issues during the tear down phase. When I attempt to close the application I am testing with SWTBot I receive the following exception: org.eclipse.swt.SWTException: Device is disposed. I was wondering if you had any insight into whether this was an issue with Eclipse, SWTBot, or something that I should look deeper into in my own project?

    Reply
    1. Lorenzo Bettini Post author

      Can you share an example? Or you could try to post in the SWTBot forum with a reproducible example.

      Reply
  2. Ejner Borgbjerg

    I tried simply copying the MathUtilsWindowTest class -> MathUtilsWindow2ndTest.
    (as it would be pleasant to have several classes with tests in them, of course).

    When I run both these classes (from Eclipse), the tests pass; However, in the console output, I get:

    Exception in thread “Thread-2” org.eclipse.swt.SWTException: Invalid thread access
    at org.eclipse.swt.SWT.error(SWT.java:4397)
    at org.eclipse.swt.SWT.error(SWT.java:4312)
    at org.eclipse.swt.SWT.error(SWT.java:4283)
    at org.eclipse.swt.widgets.Widget.error(Widget.java:481)
    at org.eclipse.swt.widgets.Shell.(Shell.java:263)
    at org.eclipse.swt.widgets.Shell.(Shell.java:254)
    at org.eclipse.swt.widgets.Shell.(Shell.java:205)
    at org.eclipse.swt.widgets.Shell.(Shell.java:141)
    at mathutils.ui.MathUtilsWindow.createContents(MathUtilsWindow.java:57)
    at mathutils.ui.MathUtilsWindow.open(MathUtilsWindow.java:43)
    at mathutils.ui.tests.MathUtilsWindowTest$1.run(MathUtilsWindowTest.java:30)
    at java.lang.Thread.run(Thread.java:701)

    Did anyone else see a similar behavior ?

    Reply
    1. Lorenzo Bettini Post author

      Do you get the exception when the second test starts? It might be the case to close the current application in an @AfterClass method…

      Reply
  3. Ejner Borgbjerg

    Yes, the exception is thrown from the second test’s run().

    I tried a few ideas, but so far didn’t succeed in getting rid of the exception.

    The problem seems to be, that SWT has registered a lock by the first thread, and the lock isn’t yet released, when the second thread starts ?

    I tried things like, in @AfterClass, to stop() the first thread (yes, I know, that’s deprecated – I just did it for the experiment); Also tried to dispose() the shell from the first instance – but got another “Invalid thread access” exception, probably for the same reason as the original one.

    I will still try a few other ideas (assuming I get any 🙂 )

    Reply
    1. Lorenzo Bettini Post author

      I’m experiencing this problem too, when I tried to implement to tests (after refactoring the main test class in an abstract base class); I’m investigating this problem… probably we should not use static fields and methods and we should try to use @Before and @After methods… I’ll post updates if I find a solution.

      Reply
  4. Lorenzo Bettini Post author

    Ejner, I’ve updated the post and the source code; now you can run several tests 🙂

    Reply
    1. Lorenzo Bettini Post author

      Not yet: I never had to run SwtBot tests from the command line since I run them using headless build technologies… if I have some spare time I’ll try to dig into that and let you know 🙂

      Reply
  5. John Henckel

    Thanks for your instructions. I have an SWT application and successfully launch it, wrap its shell with SWTBot, and issue actions. However, I can’t figure out how to use the SWT Recorder to generate action code. Can you give some advice? Does the recorder work for RPC apps only? Do I need to convert my SWT app into an Eclipse RPC app?

    Reply
    1. Lorenzo Bettini Post author

      I think the recorder requires RCP.. Or maybe it’s just a matter of adding the recorder bundles to your application.. You may want to ask in the forum..

      Reply
  6. Ejner Borgbjerg

    Hi!
    On MacOSX / Cocoa, there seems to be a restriction, in that the SWT GUI has to run in the main application thread. This leads to exceptions being thrown, if we run the code there.
    Likely the code can be rewritten, to let the GUI run in the main thread, while all SWTBot and other code is pushed to other thread(s) – if MacOS has to be supported, of course.

    Reply
    1. Lorenzo Bettini Post author

      Hi Ejner
      I don’t have any Mac to try it on… if you have one and can fix this problem so that it works on Mac as well, please submit a pull request to the github repository. 🙂
      Please keep me posted!

      Reply
  7. Bernhard Pieber

    Hi Lorenzo,

    Thanks for the detailed example. I tried to get the tests running on OS X and it seems I run into the mentioned Cocoa restriction. I cloned from GitHub and die mvn clean verify in mathutils.build. See a part of the output below. I just wanted to let you know. So far I have not found an elegant solution.

    Cheers,
    Bernhard

    ——————————————————-
    T E S T S
    ——————————————————-
    Running mathutils.ui.tests.MathUtilsNonValidInputWindowTest
    ***WARNING: Display must be created on main thread due to Cocoa restrictions.
    org.eclipse.swt.SWTException: Invalid thread access
    at org.eclipse.swt.SWT.error(SWT.java:4441)
    at org.eclipse.swt.SWT.error(SWT.java:4356)
    at org.eclipse.swt.SWT.error(SWT.java:4327)
    at org.eclipse.swt.widgets.Display.error(Display.java:1094)
    at org.eclipse.swt.widgets.Display.createDisplay(Display.java:846)
    at org.eclipse.swt.widgets.Display.create(Display.java:829)
    at org.eclipse.swt.graphics.Device.(Device.java:130)
    at org.eclipse.swt.widgets.Display.(Display.java:720)
    at org.eclipse.swt.widgets.Display.(Display.java:711)
    at org.eclipse.swt.widgets.Display.getDefault(Display.java:1414)
    at mathutils.ui.MathUtilsWindow.open(MathUtilsWindow.java:39)
    at mathutils.ui.tests.AbstractMathUtilsWindowTest$1.run(AbstractMathUtilsWindowTest.java:35)
    at java.lang.Thread.run(Thread.java:745)
    Tests run: 3, Failures: 0, Errors: 3, Skipped: 0, Time elapsed: 1.134 sec <<< FAILURE! – in mathutils.ui.tests.MathUtilsNonValidInputWindowTest
    testEmptyInput(mathutils.ui.tests.MathUtilsNonValidInputWindowTest) Time elapsed: 0.002 sec <<< ERROR!
    java.lang.IllegalStateException: Could not find a display
    at org.eclipse.swtbot.swt.finder.utils.SWTUtils.display(SWTUtils.java:250)
    at org.eclipse.swtbot.swt.finder.finders.ControlFinder.(ControlFinder.java:83)
    at org.eclipse.swtbot.swt.finder.finders.ControlFinder.(ControlFinder.java:73)
    at org.eclipse.swtbot.swt.finder.SWTBot.(SWTBot.java:115)
    at org.eclipse.swtbot.swt.finder.SWTBotTestCase.(SWTBotTestCase.java:41)
    at mathutils.ui.tests.AbstractMathUtilsWindowTest.(AbstractMathUtilsWindowTest.java:16)
    at mathutils.ui.tests.MathUtilsNonValidInputWindowTest.(MathUtilsNonValidInputWindowTest.java:8)

    testNonValidInput(mathutils.ui.tests.MathUtilsNonValidInputWindowTest) Time elapsed: 0 sec <<< ERROR!
    java.lang.IllegalStateException: Could not find a display
    at org.eclipse.swtbot.swt.finder.utils.SWTUtils.display(SWTUtils.java:250)
    at org.eclipse.swtbot.swt.finder.finders.ControlFinder.(ControlFinder.java:83)
    at org.eclipse.swtbot.swt.finder.finders.ControlFinder.(ControlFinder.java:73)
    at org.eclipse.swtbot.swt.finder.SWTBot.(SWTBot.java:115)
    at org.eclipse.swtbot.swt.finder.SWTBotTestCase.(SWTBotTestCase.java:41)
    at mathutils.ui.tests.AbstractMathUtilsWindowTest.(AbstractMathUtilsWindowTest.java:16)
    at mathutils.ui.tests.MathUtilsNonValidInputWindowTest.(MathUtilsNonValidInputWindowTest.java:8)

    testNonValidIntegerInput(mathutils.ui.tests.MathUtilsNonValidInputWindowTest) Time elapsed: 0 sec <<< ERROR!
    java.lang.IllegalStateException: Could not find a display
    at org.eclipse.swtbot.swt.finder.utils.SWTUtils.display(SWTUtils.java:250)
    at org.eclipse.swtbot.swt.finder.finders.ControlFinder.(ControlFinder.java:83)
    at org.eclipse.swtbot.swt.finder.finders.ControlFinder.(ControlFinder.java:73)
    at org.eclipse.swtbot.swt.finder.SWTBot.(SWTBot.java:115)
    at org.eclipse.swtbot.swt.finder.SWTBotTestCase.(SWTBotTestCase.java:41)
    at mathutils.ui.tests.AbstractMathUtilsWindowTest.(AbstractMathUtilsWindowTest.java:16)
    at mathutils.ui.tests.MathUtilsNonValidInputWindowTest.(MathUtilsNonValidInputWindowTest.java:8)

    Running mathutils.ui.tests.MathUtilsValidWindowTest
    Tests run: 2, Failures: 0, Errors: 2, Skipped: 0, Time elapsed: 0.007 sec <<< FAILURE! – in mathutils.ui.tests.MathUtilsValidWindowTest
    testBaseCase(mathutils.ui.tests.MathUtilsValidWindowTest) Time elapsed: 0 sec <<< ERROR!
    java.lang.IllegalStateException: Could not find a display
    at org.eclipse.swtbot.swt.finder.utils.SWTUtils.display(SWTUtils.java:250)
    at org.eclipse.swtbot.swt.finder.finders.ControlFinder.(ControlFinder.java:83)
    at org.eclipse.swtbot.swt.finder.finders.ControlFinder.(ControlFinder.java:73)
    at org.eclipse.swtbot.swt.finder.SWTBot.(SWTBot.java:115)
    at org.eclipse.swtbot.swt.finder.SWTBotTestCase.(SWTBotTestCase.java:41)
    at mathutils.ui.tests.AbstractMathUtilsWindowTest.(AbstractMathUtilsWindowTest.java:16)
    at mathutils.ui.tests.MathUtilsValidWindowTest.(MathUtilsValidWindowTest.java:8)

    testValidInput(mathutils.ui.tests.MathUtilsValidWindowTest) Time elapsed: 0.003 sec <<< ERROR!
    java.lang.IllegalStateException: Could not find a display
    at org.eclipse.swtbot.swt.finder.utils.SWTUtils.display(SWTUtils.java:250)
    at org.eclipse.swtbot.swt.finder.finders.ControlFinder.(ControlFinder.java:83)
    at org.eclipse.swtbot.swt.finder.finders.ControlFinder.(ControlFinder.java:73)
    at org.eclipse.swtbot.swt.finder.SWTBot.(SWTBot.java:115)
    at org.eclipse.swtbot.swt.finder.SWTBotTestCase.(SWTBotTestCase.java:41)
    at mathutils.ui.tests.AbstractMathUtilsWindowTest.(AbstractMathUtilsWindowTest.java:16)
    at mathutils.ui.tests.MathUtilsValidWindowTest.(MathUtilsValidWindowTest.java:8)

    Results :

    Tests in error:
    MathUtilsNonValidInputWindowTest.:8->AbstractMathUtilsWindowTest.:16->SWTBotTestCase.:41 » IllegalState
    MathUtilsNonValidInputWindowTest.:8->AbstractMathUtilsWindowTest.:16->SWTBotTestCase.:41 » IllegalState
    MathUtilsNonValidInputWindowTest.:8->AbstractMathUtilsWindowTest.:16->SWTBotTestCase.:41 » IllegalState
    MathUtilsValidWindowTest.:8->AbstractMathUtilsWindowTest.:16->SWTBotTestCase.:41 » IllegalState
    MathUtilsValidWindowTest.:8->AbstractMathUtilsWindowTest.:16->SWTBotTestCase.:41 » IllegalState

    Tests run: 5, Failures: 0, Errors: 5, Skipped: 0

    [INFO] ————————————————————————
    [INFO] Reactor Summary:
    [INFO]
    [INFO] mathutils.build ……………………………… SUCCESS [ 22.842 s]
    [INFO] mathutils.core ………………………………. SUCCESS [ 1.512 s]
    [INFO] mathutils.core.tests …………………………. SUCCESS [ 2.968 s]
    [INFO] mathutils.ui ………………………………… SUCCESS [ 0.172 s]
    [INFO] mathutils.ui.tests …………………………… FAILURE [ 4.349 s]
    [INFO] ————————————————————————
    [INFO] BUILD FAILURE
    [INFO] ————————————————————————

    Reply
    1. Lorenzo Bettini Post author

      Hi Bernhard

      as I said in previous answer I don’t have a Mac so I can’t try it.

      Can you run the ui.tests from Eclipse?

      As for the Maven/Tycho build, I think I should have added JVM flags to be enabled when run on Mac in the mathutils.ui.tests/pom.xml; something like the profile you find here: https://github.com/LorenzoBettini/xtext-maven-example/blob/master/language/2-full/org.xtext.builddsl.tests/pom.xml#L30-L42

      Could you please try in your fork?

      thanks
      Lorenzo

      Reply
      1. Bernhard Pieber

        Thank you for the ultrafast response! I added the JVM flags (see my fork). However, the results are the same when running mvn clean verify from the command line.

        I tried importing the projects into Eclipse Luna as Maven projects. (It installed some Maven plugin connectors for tyco). I did Maven > Update Project. However, I am stuck with the following build problem in mathutils.ui.tests:

        Description Resource Path Location Type
        Bundle ‘org.eclipse.swtbot.go’ cannot be resolved MANIFEST.MF /mathutils.ui.tests/META-INF line 7 Plug-in Problem

        The other projects build fine. Is there anything I have to do in addition?

        I really appreciate your help.

        Cheers,
        Bernhard

        Reply
  8. Ejner Borgbjerg

    It is possible to rewrite the tests in a systematic way, ugly but perhaps automatizable. You can see an example in my project https://sourceforge.net/projects/chessshellforpc/ .
    In the ‘source_snapshot’ folder, look in ‘test_mac’ dir.
    It shows that it’s possible to make it work on Mac / Cocoa by rewriting to take the mentioned restriction there into account.
    To make the test code less ugly, I don’t know how – I didn’t have time to try for that.

    Reply
  9. Lorenzo Bettini Post author

    The URL seems to be broken…
    but could you please try to add the lines I mentioned in the pom.xml?

    Reply

Leave a Reply