Top 7 JavaFX Testing Mistakes You Need To Avoid!

 

Transcript:

No more trial and error approach when testing JavaFX. Here are top seven mistakes when testing JavaFX applications and ways to avoid them using the test fix framework. Mistake number one, updating the UI of the fixed thread. JavaFX creates an application thread when the application starts and only this thread can render the UI elements. But the tests run on the GUI thread and so if you try to perform the UI actions, it may result in illegal state exception, random null pointer exceptions or deadlocks. So what can we do right to the UI to mutate controls on the fixed thread? If you use the aix robot class, you can wrap the interactions using the robot interact method. read from the UI to get text snapshot pixels or query the layout also on the fixed thread and return a value.

Mistake number two, incorrect bootstrapping when using spring boot. Test a fix owns the stage, spring boot owns the beans. So if you boot spring without giving it the testix stage, the beans won't be able to use it. Plus, if you use FXML, FXML loader uses a different class loader from that of Spring. Controllers that Spring create aren't of the same type as the FXML asks for. So, what can we do? Make FXML loader use the same class loader as Spring in the application code. Use the start annotation to wire up the real stage and dependency injection to inject fakes. Don't call new FXML application start if uh this code boots spring internally.

Mistake number three confusing handler wiring with the real user input. If you call the controller methods directly in the UI tests, you are testing the code wiring not the real event path. As a result, your tests may pass but miss important box or the tests may hang and fail because the input never fired. What can we do? Well, obviously avoid calling the controller methods directly in the UI tests. Use robot click on or similar methods to test user interaction and UI behavior such as pressed or visuals and so on. Use button fire or similar control methods to assert handler effect. In the headless mode, if the platform can do something like going full screen, assert proxy signal like pseudo classes or button state.

Mistake number four, bracing the fix event Q. JavaFX is a single thread kit. So the UI events get cued. If you assert in tests before the queue is drained, you are testing the UI that doesn't exist yet. Therefore, tests pass or fail unpredictably depending on the TI CPU moon cycles or what not. What can we do in the case of simple changes? You can use the uh wait for a sync utils class and its method wait for fix events. This method helps to wait before the event Q of the UI is trained. In the case you are waiting for observed outcomes, you can use the wait for method to wait for some condition to be met.

Mistake number five, assuming pixel perfect quality across platforms. The pixel colors of JavaFX can differ slightly on various platforms due to various reasons. If the tests assert the exact RGB equality on all platforms, the tests may pass locally and fail in CI or on another machine. So what can we do? Don't assert the exact color. Compare baseline to the change state and allow for some tolerance in color and pixel density. In addition, we can allow for a small absolute difference when comparing colors. sample pixels inside the shape, not near borders. This will help to avoid having different colors if the borders uh blend with the background.

Mistake number six, misconfiguring headless CI. Running JavaFX tests in CI differs from the standard testing process. These tests must run in headless state and be backed by monocle. But it is not enough to simply wire the monocle. Tests that pass locally may fail in CI due to multiple reasons. UI tests that run in parallel. Required modules are locked down. Tests assert platform features that don't exist in headless mode like full screen. So what can we do? Well, first thing first, add the dependency for the monocle. Then specify all required modules in a separate plug-in with the add opens flag.

The demo applications that I use in this video were developed and compiled NCI using uh Liberica JDK bundled with JavaX. So there was no need to add any extra dependencies on JavaFX. But if you add the dependencies on JavaFX manually, you may have to use the additional add exports flag. It allows compile time access to Glass internals. Then in the workflow file, make sure to install all necessary native libraries for JavaFX. Then run the tests with the correct profile. Don't forget to install Java or add the dependencies on Javaix or you can install the JDK with Javaix bundled already.

So for instance, the file on the screen installs Libera JDK 21 with Javaix in the setup Java action. Mistake number seven, entangling business logic with the UI. Last but not least, testing business logic with the UI is not the best practice. Just as you separate controller and service methods uh in tests for web apps, you should separate testing the business logic and the UI in JavaSix applications. The domain logic tests should not coexist with the UI test in one class. So what can we do? The best solution would be to move the business logic to a separate view and test it with a plain JUnit tests. 

Summary

This video explains the seven most common mistakes when testing JavaFX applications with TestFX and how to avoid them. It covers errors such as updating the UI outside the FX thread, incorrect Spring Boot integration, calling controller methods directly instead of simulating real user input, racing the JavaFX event queue, relying on pixel-perfect comparisons across platforms, misconfiguring headless CI with Monocle, and mixing business logic tests with UI tests. For each mistake, the video provides practical solutions like using interact(), unifying class loaders for FXML, using robot actions instead of direct method calls, waiting for the event queue to drain, allowing color tolerance in pixel tests, properly setting up CI with required modules, and separating domain logic into plain JUnit tests.

About Catherine

Java developer passionate about Spring Boot. Writer. Developer Advocate at BellSoft

Social Media

Videos
card image
Feb 6, 2026
Backend Developer Roadmap 2026: What You Need to Know

Backend complexity keeps growing, and frameworks can't keep up. In 2026, knowing React or Django isn't enough. You need fundamentals that hold up when systems break, traffic spikes, or your architecture gets rewritten for the third time.I've been building production systems for 15 years. This roadmap covers three areas that separate people who know frameworks from people who can actually architect backend systems: data, architecture, and infrastructure. This is about how to think, not what tools to install.

Videos
card image
Jan 29, 2026
JDBC Connection Pools in Microservices. Why They Break Down (and What to Do Instead)

In this livestream, Catherine is joined by Rogerio Robetti, the founder of Open J Proxy, to discuss why traditional JDBC connection pools break down when teams migrate to microservices, and what is a more efficient and reliable approach to organizing database access with microservice architecture.

Further watching

Videos
card image
Feb 27, 2026
Spring Developer Roadmap 2026: What You Need to Know

Spring Boot is powerful. But knowing the framework isn’t the same as understanding backend engineering. In this video, I walk through the roadmap I believe matters for a Spring developer in 2026. We start with data. That means real SQL — CTEs, window functions, normalization trade-offs — and understanding what ACID and BASE actually imply for system guarantees. Spring Data JPA is useful, but you still need to know what happens underneath. Then architecture: microservices vs modular monolith, serverless, CQRS, and when HTTP, gRPC, Kafka, or WebSockets make sense. Not as buzzwords — but as design choices with trade-offs. Security and infrastructure follow: OWASP Top 10, AuthN vs AuthZ, encryption in transit and at rest, Docker, Kubernetes, Infrastructure as Code, and observability with Micrometer, OpenTelemetry, and Grafana. This roadmap isn’t about mastering every tool. It’s about knowing what affects reliability in production.

Videos
card image
Feb 18, 2026
Build Typed AI Agents in Java with Embabel

Most Java AI demos stop at prompt loops. That doesn't scale in production. In this video, we integrate Embabel into an existing Spring Boot application and build a multi-step, goal-driven agent for incident triage. Instead of manually orchestrating prompt → tool → prompt cycles, we define typed actions and let the agent plan across deterministic and LLM-powered steps. We parse structured input with Ollama, query MongoDB deterministically, classify risk using explicit thresholds, rank affected implants, generate a constrained root cause hypothesis, and produce a bounded containment plan. LLM handles reasoning. Java enforces rules. This is about controlled AI workflows on the JVM — not prompt glue code.

Videos
card image
Feb 12, 2026
Spring Data MongoDB: From Repositories to Aggregations

Spring Data MongoDB breaks down fast once CRUD meets production—real queries, actual data volumes, analytics. What looks simple at first quickly turns into unreadable repository methods, overfetching, and slow queries. In this video, I walk through building a production-style Spring Boot application using Spring Data MongoDB — starting with basic setup and repositories, then moving into indexing, projections, custom queries, and aggregation pipelines. You'll see how MongoDB's document model changes data design compared to SQL, when embedding helps, and when it becomes a liability. We cover where repository method naming stops scaling, how to use @Query safely, when to switch to MongoTemplate, and how to reduce payload size with projections and DTOs. Finally, we implement real MongoDB aggregations to calculate analytics directly in the database and test everything against a real MongoDB instance using Testcontainers. This is not another MongoDB overview. It's a practical guide to actually using Spring Data MongoDB in production without fighting the database.