JavaFX Automated Testing

JavaFX Automated Testing

Test LogoRRR with TestFX

LogoRRR uses TestFX to run integration tests against its JavaFX user interface. These tests give confidence that core workflows survive new features, refactorings, and dependency updates — and they catch regressions that unit tests simply cannot see.

Why now

After 20+ releases, LogoRRR had grown complex enough that manual testing alone was no longer sufficient. The codebase needed a safety net. TestFX makes it possible to drive the actual application window — clicking buttons, opening files, inspecting UI state — from JUnit test methods.

The decision of when to invest in end-to-end tests is always a trade-off. Early in a project, UIs change too fast for tests to keep up. But once the core flows stabilise, tests become an accelerant rather than a burden. That inflection point arrived with 24.3.0.

Implementation

Scala’s concise syntax lends itself naturally to building a small test DSL. Each atomic action — open a file, click the close button, assert the tab pane is empty — becomes a readable building block:

@Test def openAndCloseTab(): Unit = {
    checkForEmptyTabPane()
    openFile(path)
    checkForNonEmptyTabPane()
    clickOn(lookup(UiNodes.LogFileHeaderTabs).query[StackPane](), MouseButton.SECONDARY)
    waitAndClickVisibleItem(CloseTabMenuItem.uiNode(fileId))
    checkForEmptyTabPane()
}

Writing frontend tests forced improvements to the production code too. A new Service layer was added to abstract file I/O and external process calls — changes that improved the architecture independently of any test benefit.

What the tests caught

  • Application shutdown behaviour — resources that were never properly cleaned up became obvious under test
  • Test isolation — each test must set up and tear down its own state, which exposed several subtle assumptions about shared UI state
  • Performance baseline — keeping an eye on test execution time prevents slow accumulation of sluggish tests
TestFX running the LogoRRR test suite — the same interactions a user would perform, executed automatically

Header photo by Sora Shimazaki on Pexels.