Décrit comment tester le code JavaFX à l'aide de TestFX, une bibliothèque de test pour JavaFX.
Une bibliothèque pour implémenter des tests dans JavaFX. Vous pouvez utiliser cette bibliothèque pour implémenter des tests d'interface utilisateur ainsi que des tests unitaires. La licence est EUPL v1.1. Cette fois, je vais essayer d'utiliser 4 séries. Depuis janvier 2017, lorsque cet article a été écrit, `` 4.0.5-alpha '' est le dernier.
Lorsque j'implémente et exécute un test qui inclut une application JavaFX ou une classe JavaFX à l'aide de JUnit standard, j'obtiens `` java.lang.ExceptionInInitializerError '' comme indiqué ci-dessous.
StackTrace
java.lang.ExceptionInInitializerError
at sun.reflect.GeneratedSerializationConstructorAccessor2.newInstance(Unknown Source)
at java.lang.reflect.Constructor.newInstance(Unknown Source)
at org.objenesis.instantiator.sun.SunReflectionFactoryInstantiator.newInstance(SunReflectionFactoryInstantiator.java:40)
at org.objenesis.ObjenesisBase.newInstance(ObjenesisBase.java:59)
at org.mockito.internal.creation.jmock.ClassImposterizer.createProxy(ClassImposterizer.java:128)
... Omis ...
at org.mockito.Mockito.mock(Mockito.java:1120)
at jp.toastkid.loto6.Loto6ControllerTest.setUpTarget(Loto6ControllerTest.java:38)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
... Omis ...
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.run(RemoteTestRunner.java:382)
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.main(RemoteTestRunner.java:192)
Caused by: java.lang.IllegalStateException: Toolkit not initialized
at com.sun.javafx.application.PlatformImpl.runLater(PlatformImpl.java:273)
... Omis ...
at javafx.scene.control.Control.<clinit>(Control.java:87)
... 37 more
Caused by: java.lang.IllegalStateException:Boîte à outils non initialisée.[How do you unit test a JavaFX controller with JUnit](http://stackoverflow.com/questions/11385604/how-do-you-unit-test-a-javafx-controller-with-junit)Il semble que cela puisse être implémenté en utilisant la méthode décrite dans, mais c'est un peu compliqué ... J'ai donc décidé d'utiliser la bibliothèque existante.
## Environnement et autres
Cette mise en œuvre et cette confirmation ont été effectuées dans l'environnement suivant.
| Java SE | 1.8.0_102
|:---|:---
| OS | Windows 10
| Eclipse | 4.5
| JFoenix | 1.0.0
| JUnit | 4.11
| Mockito | 1.9.5
| TestFX | 4.0.5-alpha
----
# Présentation de la bibliothèque
Pour Gradle, tout ce que vous avez à faire est d'ajouter une ligne de dépendances testCompile aux dépendances.
#### **`build.Correction de gradle`**
```groovy
testCompile group: 'org.testfx', name: 'testfx-junit', version: '4.0.5-alpha'
Alternativement, ce format est très bien.
build.Correction de gradle
testCompile 'org.testfx:testfx-junit:4.0.5-alpha'
Si vous utilisez un outil de compilation autre que Gradle, veuillez vérifier sur mvnrepository.com.
Les goyaves etc. sont inclus en tant que dépendances.
dependencies
org.testfx:testfx-junit:4.0.5-alpha
\--- org.testfx:testfx-core:4.0.5-alpha
+--- com.google.guava:guava:20.0
+--- org.hamcrest:hamcrest-core:1.3
\--- com.google.code.findbugs:annotations:3.0.1u2
+--- net.jcip:jcip-annotations:1.0
\--- com.google.code.findbugs:jsr305:3.0.1
La classe de test hérite de la classe org.testfx.framework.junit.ApplicationTest
. Il semble que jusqu'à la 3e série a été nommée GuiTest ''. Dans la 4ème série, il a été renommé ApplicationTest. Cette classe doit implémenter la méthode
public void start (Stage stage) throws Exception ''.
Dans TestFX, le style principal consiste à écrire des tests pour la classe Controller.
Cette fois, je vais implémenter le test dans application JavaFX qui exécute des scripts que j'ai créée plus tôt.
J'ai un écran comme celui-ci. Le code de Groovy entré par l'utilisateur est changé en ScriptEngine. api / javax / script / ScriptEngine.html), et cliquez sur le bouton qui dit exécuter pour afficher le résultat de l'exécution du script. Le côté gauche de l'écran est le CodeArea (TextArea) qui accepte l'entrée de code de l'utilisateur, et le côté gauche est le CodeArea (TextArea) qui affiche le résultat de l'exécution.
Initialisez et affichez l'interface graphique dans cette méthode. Il est exécuté avant la méthode avec @Before. Cette fois, je décrirai le processus d'initialisation avant d'afficher l'écran en fonction de l'implémentation de la classe qui appelle Controller.
Test class
@Override
public void start(final Stage stage) throws Exception {
try {
final FXMLLoader loader
= new FXMLLoader(getClass().getClassLoader().getResource("scenes/Main.fxml"));
final VBox loaded = (VBox) loader.load();
controller = (Controller) loader.getController();
final Scene scene = new Scene(loaded);
stage.setScene(scene);
} catch (final IOException e) {
LOGGER.error("Scene Reading Error", e);
}
stage.show();
}
Comme mentionné ci-dessus, nous chargeons FXML, récupérons le contrôleur, initialisons la scène et la scène, et enfin affichons la scène.
Nous avons également une méthode de test vide pour exécuter JUnit's Runner.
Méthode d'essai vide
@Test
public void test() {
// NOP.
}
Lorsque vous exécutez le test JUnit, vous verrez l'écran de l'application comme indiqué ci-dessous. Puisqu'aucune autre méthode de test n'a encore été mise en œuvre, elle n'apparaîtra que pendant un moment, puis disparaîtra immédiatement.
Cette fois, j'expliquerai brièvement la demande d'écriture du test. Il a une fonction pour exécuter le code Groovy entré par l'utilisateur dans ScriptEngine et cliquez sur le bouton intitulé exécuter pour afficher le résultat de l'exécution du script. Le côté gauche de l'écran est le CodeArea (TextArea) qui accepte l'entrée de code de l'utilisateur, et le côté gauche est le CodeArea (TextArea) qui affiche le résultat de l'exécution.
Ensuite, ajoutons le code pour le test de l'interface utilisateur.
Essayez d'entrer Hello World de Groovy.
Entrez le script dans la zone de texte sur la gauche
@Test
public void test() throws InterruptedException {
final CodeArea input = (CodeArea) lookup("#scripterInput").query();
final String text = "println 'Hello world.'";
Platform.runLater(() -> input.replaceText(text));
}
Les nœuds inclus dans la scène affichée peuvent être recherchés par ID. L'ID peut être défini dans FXML ou spécifié par setId dans la classe Node. Un exemple de définition dans FXML est présenté ci-dessous.
Exemple de définition dans FXML
<CodeArea fx:id="scripterInput" prefHeight="450.0" prefWidth="500.0">
scripterinput
Recherchez le nœud avec l'ID nommé codearea, transtypez-le dans la classe d'implémentation codearea et utilisez-le dans les tests suivants.
Lookup->cast
final CodeArea input = (CodeArea) lookup("#scripterInput").query();
Sur la classe de test JUnit, lors de la définition d'une valeur pour JavaFX Control, elle échouera à moins que vous n'utilisiez `` Platform.runLater ''.
Platform.runLater(() -> input.replaceText(text));
Lorsque vous exécutez le test, l'écran s'affiche avec le script saisi comme indiqué ci-dessous.
Le code pour obtenir le Button qui dit exécuter avec Lookup et exécuter l'événement set peut être écrit sur une ligne ci-dessous.
Lookup->query->fireEvent
Platform.runLater(() -> lookup("#runButton").query().fireEvent(new ActionEvent()));
Puisque le bouton d'exécution est spécifié dans FXML pour exécuter une méthode appelée runScript de la classe Controller, cette méthode est exécutée et CodeArea (TextArea) sur le côté droit de l'écran est le résultat de l'exécution du script
Hello world ''. `` s'affiche.
Tout ce que vous avez à faire est de vérifier la valeur avec la méthode assert.
Code de test final
@Test
public void test() throws InterruptedException {
final CodeArea input = (CodeArea) lookup("#scripterInput").query();
final String text = "println 'Hello world.'";
Platform.runLater(() -> {
input.replaceText(text);
assertEquals(text, input.getText());
lookup("#runButton").query().fireEvent(new ActionEvent());
assertEquals(
"Hello world.",
((CodeArea) lookup("#scripterOutput").query()).getText().trim()
);
});
}
L'exécution de la méthode est asynchrone à l'intérieur et à l'extérieur de Platform.runLater, donc si vous souhaitez inspecter la valeur de Node causée par les modifications apportées à Node dans Platform.runLater, vous devez l'écrire dans Platform.runLater.
Comme exemple d'échec, le code ci-dessous échoue toujours car la vérification avec assertEquals est effectuée avant input.replaceText (text)
in Platform.runLater.
Cas où l'inspection échoue
Platform.runLater(() -> input.replaceText(text));
assertEquals(text, input.getText());
Vous pouvez également écrire le même code en utilisant la Whitebox de Mockito sans utiliser la recherche de TestFX (Remarque: le contrôleur doit avoir son propre objet Node).
@Test
public void test_mockito() throws InterruptedException {
final CodeArea input = (CodeArea) Whitebox.getInternalState(controller, "scripterInput");
final String text = "println 'Hello world.'";
Platform.runLater(() -> {
input.replaceText(text);
assertEquals(text, input.getText());
((Button) Whitebox.getInternalState(controller, "runButton")).fireEvent(new ActionEvent());
assertEquals(
"Hello world.",
((CodeArea) Whitebox.getInternalState(controller, "scripterOutput")).getText().trim()
);
});
}
L'avantage d'utiliser Mockito est que vous pouvez exécuter des tests sans afficher l'écran. Cette méthode est recommandée pour ceux qui sont ennuyés par l'affichage de l'écran à chaque fois.
Jusqu'à présent, nous avons brièvement décrit comment écrire des tests pour les applications JavaFX à l'aide de TestFX. Vous pourriez penser que c'est ennuyeux de voir l'écran chaque fois que vous exécutez un test. C'est ennuyant. Si vous souhaitez tester sans afficher l'écran, il est préférable d'utiliser Mock pour créer le test. Même dans ce cas, TestFX facilite l'écriture de tests car vous n'avez pas à gérer vous-même les parties liées aux threads de JavaFX. Je ne l'ai pas présenté cette fois, mais si vous voulez écrire un test unitaire pour votre propre composant JavaFX, vous pouvez utiliser ce TestFX.
Il y a déjà beaucoup d'informations sur TestFX en anglais et en japonais.
Il y a beaucoup d'informations sur le 3ème système.
Recommended Posts