test/UI thread timing issue

92 views
Skip to first unread message

Chris Merrill

unread,
Apr 10, 2016, 11:26:21 AM4/10/16
to TestFX
I have a test that always passes when it runs first and fails when run after another test.

The test is very simple:

Node title = lookup("title1").query();
Assert.assertNotNull(title);

Further, if I add Thread.sleep(10) before it queries for the node, it always passes.

Manual inspection of the UI, if I put a breakpoint on the first line of the test, indicates the UI has not yet displayed correctly. When I add the sleep(10) and put a breakpoint after it, visual inspection indicates the UI is ready.

Questions:
1) Is this a bug or known behavior?
2) Assuming that the sleep() call is not the recommended method for dealing with this, what is the correct way?
3) Is there any other information I can provide?


TIA!
Chris


Chris Merrill

unread,
Apr 10, 2016, 2:48:45 PM4/10/16
to TestFX
Perhaps I've solved my own problem. Searching back through posts in this group related to threading or synchronization, I found the 12/2/14 post by Benjamin Gudehus that included a reference to waitForFxEvents().

So I added this to my test class:

    @Before
    public void waitForUiEvents()
        {
        WaitForAsyncUtils.waitForFxEvents();
        }

and that seems to alleviate the synchronization problem. Putting that into my own base class for TestFX tests should solve it for all my tests in the future, I hope.

Please let me know if this is NOT a good way to solve this...or could have undesirable side-effects.

I'm curious if I'm doing something to aggravate this particular symptom?  If not, then maybe this should be called before all tests by TestFX, rather than by every end-user's tests?

TIA!
Chris

Benjamin Gudehus

unread,
Apr 11, 2016, 7:59:54 AM4/11/16
to Chris Merrill, TestFX
Hey,

>1) Is this a bug or known behavior?
 
FxToolkit and ApplicationTest initialize the stages within the JavaFX application thread and wait for it to finish. Also most of the FxRobot (or ApplicationTest) methods (clickOn(), type()) synchronize the current thread with the JavaFX application thread using a semaphore (per default five acquire-releases). It was important to minimize these synchronizations (e.g. clickOn() uses the mouse press and release events, but only synchronizes after the mouse release). These are the details; what I wanted to say is, that after stage initializiation (via FxToolkit) and user interaction (via FxRobot) the state of the nodes for state assertion (via FxAssert, or in your case JUnit Assert) should be synchronized.

>2) Assuming that the sleep() call is not the recommended method for dealing with this, what is the correct way?

Instead of Thread.sleep() you can also use FxRobot.sleep() (it is also in ApplicationTest). But yes, it is not the recommended way. I'd either call interrupt() before the assertion or put the assertion into a interact() callable. Both internally use waitForFxEvents().

>3) Is there any other information I can provide?

In general it is always good the have a SSCCE (http://www.sscce.org/) to reproduce the issue locally.

>Please let me know if this is NOT a good way to solve this...or could have undesirable side-effects.

From my experience calling interrupt() (which is the same as waitForFxEvents()) is a good way to solve this. The JavaFX application thread is always synchronized after stage setup. For robot methods (i.e. clickOn(), type(), ...) it is more difficult to decide whether to synchronize the thread. After some user feedback I minimized the synchronizations. For assertions there are no synchronization, and the tester has to decide when to synchronized the thread.

>I'm curious if I'm doing something to aggravate this particular symptom?  If not, then maybe this should be called before all tests by TestFX, rather than by every end-user's tests?

As mentioned in the previous paragraph, the assertion (and also the Node lookup) completely ignores thread synchronization. So, I think it is a general problem. However in most cases the robots are involved, and they synchronizes the threads.

--Benjamin

--
You received this message because you are subscribed to the Google Groups "TestFX" group.
To unsubscribe from this group and stop receiving emails from it, send an email to testfx-discus...@googlegroups.com.
For more options, visit https://groups.google.com/d/optout.

Chris Merrill

unread,
Apr 11, 2016, 4:04:41 PM4/11/16
to TestFX
> As mentioned in the previous paragraph, the assertion (and also the Node lookup) completely ignores thread synchronization. So, I think it is a general problem. However in most cases the robots are involved, and they synchronizes the threads.

If I understood that correctly, I may experience this problem because I'm not interacting with FxRobot before my first assertion?

> In general it is always good the have a SSCCE (http://www.sscce.org/) to reproduce the issue locally.

I'm not sure if this qualifies for the "Short" in SSCCE, but I've attached a gradle project that demonstrates the problem.

run "./gradlew test" to see 2 tests failing (.\gradlew.bat test" from a windows shell).

enable this commented-out line in src/test/java/net/christophermerrill/javafx/tests/ComponentTest.java:
//        WaitForAsyncUtils.waitForFxEvents();

then the tests will pass. The titleVisibility test is the simple example that I originally mentioned. Even without the WaitForAsyncUtils code, it will pass if it runs first and fail if it runs after another test.

Since a test that passes only in isolation frequently indicates a problem with the test design, I'm hoping someone can point that out for me :)


TIA!
Chris

testfx-synchronization-example.zip
Message has been deleted

Chris Merrill

unread,
Apr 19, 2016, 3:37:03 PM4/19/16
to TestFX
Just checking back. Wondering if my example was insufficient to demonstrate the problem?

If you're not familiar with Gradle, you don't need to have it installed to build.run the project - the gradlew script will download what it needs.


Chris

Benjamin Gudehus

unread,
Apr 20, 2016, 2:21:37 AM4/20/16
to Chris Merrill, TestFX

Hey Chris,

sorry I didn't receive your previous mail. Could you resent the attachment, please? A part of your message is cited here, but not the attachment.

Gradle is no problem :)

--Benjamin

Chris Merrill

unread,
Apr 20, 2016, 9:08:24 AM4/20/16
to TestFX, ch...@ide4selenium.com
It may have been blocked from your email because it is a zip that contains a .bat for running Gradle (GMail, for example, doesn't like that). If I attach it again, you may not get this response either.

I recommend downloading the attachment from my April 11 response on the google group:
  https://groups.google.com/forum/#!topic/testfx-discuss/3OuopHS1a_w

Chris
Reply all
Reply to author
Forward
0 new messages