I am working on a fairly large project which includes a set of custom JavaFX components. For each custom component which is meant to be reused, I have started to write a set of automated tests using JemmyFX and JUnit. During development, I run these from inside Eclipse Juno.
Running the entire suite of tests at once has proven difficult. The problem seems to stem from the fact since I want to test multiple components, I would ideally run a different application for each (so that tests performed on one component do not affect other tests).
I created a base class which does the following:
@BeforeClass public static void beforeClass() { Thread t = new Thread("JavaFX Init Thread") { @Override public void run() { Application.launch(UITester.class, new String[0]); } }; t.setDaemon(true); t.start(); }
Using this base class, I created a separate class with @Test
tests for each custom control. When I run this test suite, the first test case runs fine, but the rest fail:
Exception in thread "JavaFX Init Thread" java.lang.IllegalStateException: Application launch must not be called more than once
I have tried the following ways to address this problem:
I added the following to the base class:
@AfterClass public static void afterClass() { Platform.exit(); }
Same problem persists. Perhaps because the VM is not restarted between tests?
I put in a static variable to check and see if perhaps the application is already running. This makes the problem go away when I run the tests from Eclipse. When I run them from the command line, the problem is still there. Not good for when we try to run these tests on the integration server.
This is an odd one. I can catch the exception, and most of my problems go away, except for the fact that every 4 or 5 runs of the entire test suite Ubuntu crashes to the shell and I have to log back in.
So, how do I best write tests for a large suite of custom controls? Is my approach incorrect?
After looking at the source of MarvinFX I was able to implement our test framework in a fashion that addresses my problems. What appears to have contributed most to fix this problem was rebuilding the stage and scene for every test, as demonstrated in this (pseudo) code:
@Before
public void before() {
Node node = generateComponentToTest();
Parent parent = StackPaneBuilder.create().children(node).build();
Scene scene = SceneBuilder.create().root(parent).build();
if (this.currentStage != null) {
this.currentStage.close();
}
Stage stage = new Stage();
stage.setScene(scene);
stage.centerOnScreen();
stage.show();
this.currentStage = stage;
}