Voici un extrait de ce à quoi ressemble un test pour TestFX, tiré directement de leur GitHub README:

@ExtendWith(ApplicationExtension.class)
class ClickableButtonTest_JUnit5Hamcrest {

    private Button button;

    /**
     * Will be called with {@code @Before} semantics, i. e. before each test method.
     *
     * @param stage - Will be injected by the test runner.
     */
    @Start
    private void start(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();
    }

    /**
     * @param robot - Will be injected by the test runner.
     */
    @Test
    void should_contain_button_with_text(FxRobot robot) {
        FxAssert.verifyThat(button, LabeledMatchers.hasText("click me!"));
        // or (lookup by css id):
        FxAssert.verifyThat("#myButton", LabeledMatchers.hasText("click me!"));
        // or (lookup by css class):
        FxAssert.verifyThat(".button", LabeledMatchers.hasText("click me!"));
    }

Mon problème est, en particulier avec les actions qui changent de scènes / racines. L'aspect du contrôleur / scène en cours de test change la racine à la fin, ce qui produit la trace de pile suivante:

Caused by: java.lang.NullPointerException
    at org.example/org.example.App.setRoot(App.java:67)
    at org.example/org.example.services.AppService.setRoot(AppService.java:20)
    at org.example/org.example.controllers.SecondaryController.switchToGameScreen(SecondaryController.java:64)
    ... 57 more

Ma solution pour cela était, comme vous pourrez peut-être le constater, que j'ai créé une classe de wrapper de service pour les méthodes statiques dans App (comme setRoot provoquant le NPE), qui, si j'avais accès au contrôleur, je pourrais théoriquement me moquer avec Mockito. Malheureusement, si vous revenez à l'exemple de code ci-dessus, il ne semble pas y avoir de notion d'accès à la classe de contrôleur. Vous obtenez la création au niveau de la surface et l'interaction avec la scène, mais je ne sais pas comment accéder au contrôleur sous-jacent. Bien sûr, j'ai besoin d'accéder au contrôleur physique pour me moquer de sa classe de service.

Est-ce que quelqu'un sait comment je pourrais accéder à cette classe, afin que je puisse définir sa classe wrapper sur une version simulée?

Je peux fournir le code source si quelqu'un veut vraiment jouer avec.

0
notacorn 27 févr. 2021 à 22:45

1 réponse

Meilleure réponse

Deviner.

javafx.fxml.FXMLLoader a une méthode appelée getController. Mais ce n'est pas si simple, car le javafx.fxml.FXMLLoader doit physiquement load dans un objet javafx.scene.Parent pour que le contrôleur existe.

Quoi qu'il en soit, voici une courte configuration de bootstrap que vous pouvez suivre.

@ExtendWith(ApplicationExtension.class)
public class ToTest {
  private Controller controller;

  @Start
  public void setUp(Stage stage) throws IOException {
    FXMLLoader loader = new FXMLLoader(getClass().getResource("totest.fxml"));
    Parent root = loader.load();
    //This must happen AFTER loader.load()
    this.controller = loader.getController();
    stage.setScene(new Scene(root, 0, 0));
    stage.show();
  }
}

À partir de là, vous pouvez faire ce que vous voulez au contrôleur. (dans mon cas, se moquer)

0
notacorn 27 févr. 2021 à 20:16