Simple and clean testing for JavaFX.
TestFX requires a minimum JDK version of 8 (1.8).
- A fluent and clean API.
- Flexible setup and cleanup of JavaFX test fixtures.
- Simple robots to simulate user interactions.
- Rich collection of matchers and assertions to verify expected states of JavaFX scene-graph nodes.
Support for:
- Java 8 and 9.
- Multiple testing frameworks (Junit 4, Junit 5, and Spock).
- Hamcrest matchers or AssertJ assertions (or both!).
- Screenshots of failed tests.
- Headless testing using Monocle.
To add a dependency on TestFX using Gradle, use the following:
dependencies {
testCompile "org.testfx:testfx-core:4.0.13-alpha"
}
Next add a dependency corresponding to the testing framework you are using in
your project. TestFX supports JUnit 4, JUnit 5, and Spock. For example if
you are using JUnit 4 in your project you would add a dependency on testfx-junit
:
dependencies {
testCompile "org.testfx:testfx-junit:4.0.13-alpha"
}
To add a dependency on TestFX using Maven, use the following:
<dependency>
<groupId>org.testfx</groupId>
<artifactId>testfx-core</artifactId>
<version>4.0.13-alpha</version>
<scope>test</scope>
</dependency>
Next add a dependency corresponding to the testing framework you are using in
your project. TestFX supports JUnit 4, JUnit 5, and Spock. For example if
you are using JUnit 4 in your project you would add a dependency on testfx-junit
:
<dependency>
<groupId>org.testfx</groupId>
<artifactId>testfx-junit</artifactId>
<version>4.0.13-alpha</version>
<scope>test</scope>
</dependency>
import org.testfx.framework.junit.ApplicationTest;
public class DesktopPaneTest extends ApplicationTest {
DesktopPane desktopPane;
@Override
public void start(Stage stage) {
desktopPane = new DesktopPane();
desktopPane.setId("desktop");
Scene scene = new Scene(desktopPane, 800, 600);
stage.setScene(scene);
stage.show();
}
@Test
public void should_drag_file_into_trashcan() {
// given:
rightClickOn("#desktop").moveTo("New").clickOn("Text Document");
write("myTextfile.txt").push(KeyCode.ENTER);
// when:
drag(".file").dropTo("#trash-can");
// then:
verifyThat("#desktop", hasChildren(0, ".file"));
}
}
import org.testfx.framework.junit.ApplicationTest;
import static org.testfx.assertions.api.Assertions.assertThat;
public class DesktopPaneTest extends ApplicationTest {
DesktopPane desktopPane;
@Override
public void start(Stage stage) {
desktopPane = new DesktopPane();
desktopPane.setId("desktop");
Scene scene = new Scene(desktopPane, 800, 600);
stage.setScene(scene);
stage.show();
}
@Test
public void should_drag_file_into_trashcan() {
// given:
rightClickOn("#desktop").moveTo("New").clickOn("Text Document");
write("myTextfile.txt").push(KeyCode.ENTER);
// when:
drag(".file").dropTo("#trash-can");
// then:
assertThat(desktopPane).hasChildren(0, ".file");
// or (lookup by css id):
assertThat(lookup("#desktop").queryAs(DesktopPane.class)).hasChildren(0, ".file");
// or (look up css class):
assertThat(lookup(".desktop-pane").queryAs(DesktopPane.class)).hasChildren(0, ".file");
}
}
import org.testfx.framework.junit5.ApplicationTest;
@ExtendWith(ApplicationExtension.class)
class ClickableButtonTest {
@Start
void onStart(Stage stage) {
Button button = new Button("click me!");
button.setOnAction(actionEvent -> button.setText("clicked!"));
stage.setScene(new Scene(new StackPane(button), 100, 100));
stage.show();
}
@Test
void should_contain_button() {
// expect:
verifyThat(".button", hasText("click me!"));
}
@Test
void should_click_on_button(FxRobot robot) {
// when:
robot.clickOn(".button");
// then:
verifyThat(".button", hasText("clicked!"));
}
}
import org.testfx.framework.junit5.ApplicationTest;
import static org.testfx.assertions.api.Assertions.assertThat;
@ExtendWith(ApplicationExtension.class)
class ClickableButtonTest {
Button button;
@Start
void onStart(Stage stage) {
button = new Button("click me!");
button.setId("myButton");
button.setOnAction(actionEvent -> button.setText("clicked!"));
stage.setScene(new Scene(new StackPane(button), 100, 100));
stage.show();
}
@Test
void should_contain_button() {
// expect:
assertThat(button).hasText("click me!");
// or (lookup by css id):
assertThat(lookup("#myButton").queryAs(Button.class)).hasText("click me!");
// or (lookup by css class):
assertThat(lookup(".button").queryAs(Button.class)).hasText("click me!");
// or (query specific type):
assertThat(lookup(".button").queryButton()).hasText("click me!');
}
@Test
void should_click_on_button(FxRobot robot) {
// when:
robot.clickOn(".button");
// then:
assertThat(button).hasText("clicked!");
// or (lookup by css id):
assertThat(lookup("#myButton").queryAs(Button.class)).hasText("clicked!");
// or (lookup by css class):
assertThat(lookup(".button").queryAs(Button.class)).hasText("clicked!");
// or (query specific type)
assertThat(lookup(".button").queryButton()).hasText("clicked!");
}
}
import org.testfx.framework.spock.ApplicationSpec;
class ClickableButtonSpec extends ApplicationSpec {
@Override
void init() throws Exception {
FxToolkit.registerStage { new Stage() }
}
@Override
void start(Stage stage) {
Button button = new Button('click me!')
button.setOnAction { button.setText('clicked!') }
stage.setScene(new Scene(new StackPane(button), 100, 100))
stage.show()
}
@Override
void stop() throws Exception {
FxToolkit.hideStage()
}
def "should contain button"() {
expect:
verifyThat('.button', hasText('click me!'))
}
def "should click on button"() {
when:
clickOn(".button")
then:
verifyThat('.button', hasText('clicked!'))
}
}
- Javadocs for latest
master
- The wiki
- The changelog CHANGES.md
Head over to our gitter chat for discussion and questions.
The testfx-legacy
subproject is deprecated and no longer supported. It is highly recommended
that you switch from using testfx-legacy
. If you want to continue using it you should cap
the versions of testfx-core
and testfx-legacy
to 4.0.8-alpha
, which was the last released
version of testfx-legacy
. Using a newer version of testfx-core
with an older version of
testfx-legacy
will very likely break (and does with testfx-core
versions past 4.0.10-alpha
).
Thanks to all of the contributors of TestFX!