Over a million developers have joined DZone.
{{announcement.body}}
{{announcement.title}}

Testing JavaFX UIs: Part 2 of ?

DZone's Guide to

Testing JavaFX UIs: Part 2 of ?

· Java Zone
Free Resource

Managing a MongoDB deployment? Take a load off and live migrate to MongoDB Atlas, the official automated service, with little to no downtime.

In order to perform functional testing of a JavaFX UI ( as discussed here), we need first to start such UI from a test (written in Java) and then get a reference to the JFrame hosting it. Once we overcome this challenge, we can start simulating user input on the UI under test. Once again, easier said than done.

We already had the class ScriptLauncher that executes a JavaFX script using the Java Scripting API. The following is a simplified version of the original class:

 @RunsInEDT
public static void launch(String scriptName) {
final InputStream script = ScriptLauncher.class.getResourceAsStream(scriptName);
execute(new GuiTask() {
protected void executeInEDT() throws Throwable {
ScriptEngineManager manager = new ScriptEngineManager();
ScriptEngine engine = manager.getEngineByExtension("fx");
InputStreamReader reader = new InputStreamReader(script);
engine.eval(reader);
}
});
}

As Michael and I discovered, this approach is very fragile. If the script to launch depends on another one, this launcher will throw an exception. In another words, ScriptLauncher can only execute a JavaFX script that has no dependencies on other scripts. Lame.

My second approach involves launching a compiled JavaFX UI. While debugging ScriptEngine when it launches a JavaFX UI, I discovered that all JavaFX UIs have a static method javafx$run$, which takes a com.sun.javafx.runtime.sequence.Sequence as its only parameter. This method is like the "main" method in regular Java applications, and the ScriptEngine calls it passing TypeInfo.String.emptySequence. I gave it a try and it actually launches the JavaFX UI! Sweet!

Then I discovered that the method javafx$run$ returns a javafx.stage.Stage. I suspected that the JFrame hosting the JavaFX UI has to be there. After a few prinltns, I found a way to get a com.sun.javafx.stage.FrameStageDelegate, which, as you guessed, contains the JFrame I've been looking for. To make the story short, here is the code:

 public static JFrame launch(Class javaFxClass) {
Stage stage = (Stage) staticMethod("javafx$run$").withReturnType(Object.class)
.withParameterTypes(Sequence.class)
.in(javaFxClass)
.invoke(TypeInfo.String.emptySequence);
FrameStageDelegate frameDelegate = (FrameStageDelegate) stage.get$impl_stageDelegate().get();
return (JFrame) frameDelegate.get$window().get();
}

BTW, I'm using FEST-Reflect to call the static method javafx$run$ via Java Reflection.

The code for the new launcher can be found here.

Feedback is always appreciated

From http://www.jroller.com/alexRuiz/

MongoDB Atlas is the easiest way to run the fastest-growing database for modern applications — no installation, setup, or configuration required. Easily live migrate an existing workload or start with 512MB of storage for free.

Topics:

Opinions expressed by DZone contributors are their own.

THE DZONE NEWSLETTER

Dev Resources & Solutions Straight to Your Inbox

Thanks for subscribing!

Awesome! Check your inbox to verify your email so you can start receiving the latest in tech news and resources.

X

{{ parent.title || parent.header.title}}

{{ parent.tldr }}

{{ parent.urlSource.name }}