JavaFX - TestFX et JUnit

Maven pom.xml et configuration

<project xmlns="http://maven.apache.org/POM/4.0.0"
	xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
	xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
	<modelVersion>4.0.0</modelVersion>
	<groupId>fr.ronanlefichant</groupId>
	<artifactId>testjavafx</artifactId>
	<version>0.0.1-SNAPSHOT</version>
	<properties>
		<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
		<maven.compiler.source>11</maven.compiler.source>
		<maven.compiler.target>11</maven.compiler.target>
	</properties>
	<dependencies>
		<dependency>
			<groupId>org.openjfx</groupId>
			<artifactId>javafx-controls</artifactId>
			<version>17.0.0.1</version>
		</dependency>
		<dependency>
			<groupId>org.testfx</groupId>
			<artifactId>testfx-core</artifactId>
			<version>4.0.16-alpha</version>
			<scope>test</scope>
		</dependency>
		<dependency>
			<groupId>org.testfx</groupId>
			<artifactId>testfx-junit5</artifactId>
			<version>4.0.16-alpha</version>
			<scope>test</scope>
		</dependency>
	</dependencies>
	<build>
		<plugins>
			<plugin>
				<groupId>org.apache.maven.plugins</groupId>
				<artifactId>maven-compiler-plugin</artifactId>
				<version>3.8.0</version>
				<configuration>
					<release>11</release>
				</configuration>
			</plugin>
			<plugin>
				<groupId>org.openjfx</groupId>
				<artifactId>javafx-maven-plugin</artifactId>
				<version>0.0.6</version>
				<executions>
					<execution>
						<!-- Default configuration for running -->
						<!-- Usage: mvn clean javafx:run -->
						<id>default-cli</id>
						<configuration>
							<mainClass>fr.ronanlefichant.testjavafx.App</mainClass>
						</configuration>
					</execution>
				</executions>
			</plugin>
		</plugins>
	</build>
</project>

Important

Pour Ă©viter l'erreur suivante :

java.lang.IllegalAccessError: class org.testfx.toolkit.impl.ToolkitServiceImpl cannot access class com.sun.javafx.application.ParametersImpl (in module javafx.graphics) because module javafx.graphics does not export com.sun.javafx.application to unnamed module

Arguments VM :

--add-exports javafx.graphics/com.sun.javafx.application=ALL-UNNAMED

L'application JavaFX

package fr.ronanlefichant.testjavafx;

import javafx.application.Application;
import javafx.geometry.Insets;
import javafx.geometry.Pos;
import javafx.scene.Scene;
import javafx.scene.control.Button;
import javafx.scene.control.Label;
import javafx.scene.control.TextField;
import javafx.scene.layout.HBox;
import javafx.scene.layout.VBox;
import javafx.stage.Stage;

/**
 * JavaFX App
 */
public class App extends Application {

  @Override
  public void start(Stage stage) {

    // Élément racine
    VBox root = new VBox();

    // Élément contenant champ texte et le bouton
    HBox formHbox = new HBox();

    // Le champ texte
    TextField firstnameTextField = new TextField();
    firstnameTextField.setId("firstname-textfield");

    // Le bouton
    Button sayHelloButton = new Button("Dire bonjour");
    sayHelloButton.setId("say-hello-btn");

    // Ajoute les composants
    formHbox.getChildren().add(firstnameTextField);
    formHbox.getChildren().add(sayHelloButton);

    // Libellé pour afficher le "bonjour"
    Label helloLabel = new Label();
    helloLabel.setId("hello-label");

    // Action lors d'un clic sur le bouton
    sayHelloButton.setOnAction(event -> {
      // Libellé avec le message "Bonjour"
      helloLabel.setText("Bonjour " + firstnameTextField.getText() + " !");
    });

    // Ajoute le formulaire et le libellé
    root.getChildren().add(formHbox);
    root.getChildren().add(helloLabel);

    // Padding top de 20px
    helloLabel.setPadding(new Insets(20, 0, 0, 0));

    // Éléments centrés
    root.setAlignment(Pos.CENTER);
    formHbox.setAlignment(Pos.CENTER);

    // La scène et la fenêtre
    Scene scene = new Scene(root, 400, 300);
    stage.setScene(scene);
    stage.show();
  }

  public static void main(String[] args) {
    launch();
  }

}

Test JUnit et TestFX JavaFX

package fr.ronanlefichant.testjavafx;

import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
import org.testfx.api.FxAssert;
import org.testfx.api.FxRobot;
import org.testfx.framework.junit5.ApplicationExtension;
import org.testfx.framework.junit5.Start;
import org.testfx.matcher.control.LabeledMatchers;
import org.testfx.matcher.control.TextInputControlMatchers;

import javafx.stage.Stage;

@ExtendWith(ApplicationExtension.class)
class AppTestFx {

  /**
   * Méthode d'initialisation appelée avant chaque test
   *
   * @param stage La fenêtre (stage) injectée
   */
  @Start
  private void start(Stage stage) {
    App app = new App();
    app.start(stage);
  }

  /**
   * Vérifie si le bouton contient le texte "Dire bonjour"
   * 
   * @param robot Le FxRobot injecté
   */
  @Test
  void should_contain_button_with_text(FxRobot robot) {
    FxAssert.verifyThat("#say-hello-btn", LabeledMatchers.hasText("Dire bonjour"));
  }

  /**
   * Vérifie si le nom est bien concaténé avec "Bonjour" lors d'un clic sur "Dire
   * bonjour"
   * 
   * @param robot Le FxRobot injecté
   */
  @Test
  void should_display_bonjour_with_name(FxRobot robot) {

    robot.clickOn("#firstname-textfield");
    robot.write("Pierre");
    FxAssert.verifyThat("#firstname-textfield", TextInputControlMatchers.hasText("Pierre"));
    robot.clickOn("#say-hello-btn");
    FxAssert.verifyThat("#hello-label", LabeledMatchers.hasText("Bonjour Pierre !"));
    robot.clickOn("#firstname-textfield");
    robot.eraseText("Pierre".length());

    robot.clickOn("#firstname-textfield");
    robot.write("Paul");
    FxAssert.verifyThat("#firstname-textfield", TextInputControlMatchers.hasText("Paul"));
    robot.clickOn("#say-hello-btn");
    FxAssert.verifyThat("#hello-label", LabeledMatchers.hasText("Bonjour Paul !"));
    robot.clickOn("#firstname-textfield");
    robot.eraseText("Paul".length());

    robot.clickOn("#firstname-textfield");
    robot.write("Jacques");
    FxAssert.verifyThat("#firstname-textfield", TextInputControlMatchers.hasText("Jacques"));
    robot.clickOn("#say-hello-btn");
    FxAssert.verifyThat("#hello-label", LabeledMatchers.hasText("Bonjour Jacques !"));
    robot.clickOn("#firstname-textfield");
    robot.eraseText("Jacques".length());
  }

}

Commentaires