Attempting to use TestFX to test the Stage - Is this incorrect?

1,412 views
Skip to first unread message

David Hatten

unread,
Dec 1, 2014, 8:11:39 PM12/1/14
to testfx-...@googlegroups.com
So I'm playing around with JavaFX and trying to get a handle on things. So far I have a test that creates a button and, a combo box, and a grid, attaches the objects to a grid, then attaches the grid to an AnchorPane and returns the AnchorPane.

This works perfectly. When I run the test I see the UI elements appear on my desktop with no kind of window (I guess the JavaFX term is "stage") and the mouse interacts with them.

What I'm wondering is if it's possible to test Stage with this. So, for example, Lets say I just want to check that the title of the Stage of my application is what I think it is.

Is there a way to do this? It doesn't look obvious to me, and it might even be outside of the scope of what TestFX is intended to do.

So, am I doing things wrong, or am I doing things really wrong?

Thanks.

Benjamin Gudehus

unread,
Dec 2, 2014, 5:40:15 AM12/2/14
to testfx-...@googlegroups.com
Hi David!


>with no kind of window
That's actually the primary Stage without borders (StageStyle.UNDECORATED [1]).


>So, for example, Lets say I just want to check that the title of the Stage of my application is what I think it is.
@Test
public void should_have_stage_title() {
    // TestFX 3.x:
    verifyThat(((Stage) getWindowByIndex(0)).getTitle(), Matchers.equalTo(""));
    // TestFX 4.x:
    verifyThat(((Stage) getWindowByIndex(0)).getTitle(), Matchers.equalTo("ToolkitApplication"));
}

TestFX 4.x will allow more flexible setup of Applications, Stages, Scenes and Nodes.

--
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.

David Hatten

unread,
Dec 2, 2014, 11:40:09 AM12/2/14
to testfx-...@googlegroups.com
Okay, that makes sense. So this looks like I can't directly modify what windows or stages are being shown (I see no way to add windows to be picked up by getWindowByIndex() in a way that doesn't interfere with the TestFX default window), so I would have to directly modify that Window it seems. Which is fine for now, I'm still experimenting and getting comfortable with JavaFX (and TestFX).

I looked at the beta v4. It seems that a rather significant overhaul has happened around the "getRootNode()" method related to the new Lifecycle model, but I'm not entirely sure how to use the new Lifecycle object. It looks like you're completely retiring the GuiTest class extension in favor of this Lifecycle object. Am I parsing that right? Or should I just sit tight and wait until some documentation gets released?

Thanks for the response!

Benjamin Gudehus

unread,
Dec 2, 2014, 12:15:53 PM12/2/14
to David Hatten, testfx-...@googlegroups.com
>It looks like you're completely retiring the GuiTest class extension in favor of this Lifecycle object. Am I parsing that right?

Yes. Using the Lifecycle object will be the recommended way to setup and cleanup test fixtures. GuiTest will move to the module testfx-compat or testfx-legacy.

Here is a snippet to archive the behavior of GuiTest#getRootNode() with FxLifecycle:

target(FxLifecycle.registerPrimaryStage());
FxLifecycle.setupSceneRoot(() -> getRootNode());
FxLifecycle.setupStage((stage) -> {
    stage.show();
    stage.toBack();
    stage.toFront();
});
WaitForAsyncUtils.waitForFxEvents();

via: https://github.com/hastebrot/TestFX/blob/866bae73df/subprojects/testfx-core/src/main/java/org/loadui/testfx/GuiTest.java#L180


>Or should I just sit tight and wait until some documentation gets released?

There is a Javadoc [1] in org.testfx.api.FxLifecycle that tries to explain a bit. However it needs a bit more work. [2] tracks the current work on that.

With FxLifecycle you need to explicitly show() the primaryStage (the TestFX default window). show() needs to be called in the FX thread, that's why setupStage() uses a callback method in the example above.

You can use setup(() -> new Stage().show()) to open a custom window. If you haven't previously called show() on the primaryStage, then your custom window will be the only window in the javafx.stage.Window.impl_getWindows() list.

setupStage(), setupApplication(), setupScene() and setupSceneRoot() all use the internal field targetStage as target window for content. registerPrimaryStage() sets the primaryStage as targetStage. So if you use setupSceneRoot(() -> getRootNode()) it will attach your parent Node into the primaryStage. You can change this by calling registerTargetStage(() -> new Stage()). If you now use setupSceneRoot() it will attach your parent Node into the new targetStage that was set with the callback method.


--Benjamin

David Hatten

unread,
Dec 2, 2014, 1:18:04 PM12/2/14
to Benjamin Gudehus, testfx-...@googlegroups.com

Ohhh so I would just treat my test like a normal junit test, put the Lifecycle object in a @BeforeClass method and instantiate it there as shown. Then I use an FXRobot (like FxRobotImpl) to do things like click and find in the @Test methods themselves, right?

The stage handling in FXLifecycle makes a lot of sense; I'll be playing with this when I get home, thanks!

David Hatten

unread,
Dec 2, 2014, 1:21:37 PM12/2/14
to testfx-...@googlegroups.com, crashove...@gmail.com
Ah, I just reread your post on the 4.0 beta, confirming my FxRobotImpl question. That post makes a lot more sense now. Thanks a lot for the help!

Benjamin Gudehus

unread,
Dec 2, 2014, 1:36:27 PM12/2/14
to David Hatten, testfx-...@googlegroups.com
Yes, exactly! :)

Being able to use JUnit-specific constructs like @BeforeClass, @After and @Rule adds a lot of flexibility. Also the "extraction" of FxLifecycle and FxRobot allows easy usage with other test frameworks such as TestNG, Cucumber and Spock.

FxRobotImpl is designed to be used via inheritance or composition. For instance GuiTest extends from FxRobotImpl to have the short syntax of the instance methods (clickOn(), moveTo(), ...). Spock specifications need to extend from Specifcation, so FxRobotImpl needs to be uses via composition (fx.clickOn(), fx.moveTo()).

I once tried to split the click and find functionality in FxRobot into two classes. But there are too many dependencies, so I finally gave up. I'm just noticing that FxRobot is missing some methods for window and node lookup (window(), node(), nodes(), parantNode()). The methods for them in the FxRobot interface are commented out. These methods simply forward the calls to NodeFinderImpl and WindowFinderImpl, so I guess I can implement them easily.

Reply all
Reply to author
Forward
0 new messages