Java 9 + maven + junit: test de code de module-info.java qui lui est propre et où le mettre?

disons que j'ai un projet Java utilisant Maven 3 et junit. Il y a src/main/java et src/test/java répertoires contenant respectivement les sources principales et les sources de test (tout est standard).

maintenant je veux migrer le projet vers Java 9. src/main/java le contenu représente le module Java 9; Il y a com/acme/project/module-info.java à la recherche à peu près comme ceci:

module com.acme.project {
    require module1;
    require module2;
    ...
}

si Ce test de code <!-- 8 - Par exemple, pour ajouter une dépendance sur certains module n'est nécessaire pour les essais, pas pour le code de production. Dans ce cas, je dois mettre module-info.javasrc/test/java/com/acme/project/ donner au module un nom différent. De cette façon, Maven semble traiter les sources principales et les sources de test comme des modules différents, donc je dois exporter des paquets du module principal vers le module de test, et j'ai besoin de paquets dans le module de test, quelque chose comme ceci:

module principal (en src/main/java/com/acme/project):

module prod.module {
    exports com.acme.project to test.module;
}

module d'essai (en src/test/java/com/acme/project):

module test.module {
    requires junit;
    requires prod.module;
}

ce produit

[ERROR] Failed to execute goal org.apache.maven.plugins:maven-compiler-plugin:3.7.0:testCompile (default-testCompile) on project test-java9-modules-junit: Compilation failure: Compilation failure:
[ERROR] /home/rpuch/git/my/test-java9-modules-junit/src/test/java/com/acme/project/GreeterTest.java:[1,1] package exists in another module: prod.module

parce qu'un paquet est défini en deux modules. Donc maintenant je dois avoir différents projets dans le module principal et le module de test, ce qui n'est pas pratique.

je sens que je suis le mauvais chemin, tout commence à sembler très laid. Comment puis-je avoir module-info.java de son propre code de test, ou comment obtenir les mêmes effets (require, etc) sans elle?

18
demandé sur Roman Puchkovskiy 2017-10-06 23:05:04

3 réponses

le système de modules ne fait pas de distinction entre le code de production et le code de test, donc si vous choisissez de modulariser le code de test, le prod.module et test.module ne peuvent pas partager le même paquet com.acme.project, comme décrit dans la spécifications:

Non-ingérence - le compilateur Java, la machine virtuelle et le système d'exécution doivent s'assurer que les modules qui contiennent des paquets du même nom n'interfèrent pas entre eux. Si deux modules distincts contiennent paquets du même nom alors, du point de vue de chaque module, tous les types et membres de ce paquet sont définis uniquement par ce module. Le Code dans ce paquet dans un module ne doit pas pouvoir accéder au paquet-types privés ou membres dans ce paquet dans l'autre module.

comme indiqué par Alan Bateman, le plugin du compilateur Maven utilise --patch-module et d'autres options fourni par le système du module lors de la compilation du code dans l'arbre src/test/java, donc que le module à l'essai est complété par les classes d'essai. Et cela est également fait par le plugin Surefire lors de l'exécution des classes de test (voir prendre en charge l'exécution des tests unitaires dans nommé Java 9 modules). Cela signifie que vous n'avez pas besoin de placer votre code de test dans un module.

6
répondu manouti 2017-10-07 12:03:36

Vous pourriez voulez repenser la conception du projet que vous essayez de mettre en œuvre. Puisque vous mettez en œuvre un module et son test dans un projet, vous devez vous abstenir d'utiliser différents modules pour chacun d'eux individuellement.

il ne devrait y avoir qu'un seul module-info.java pour un module et ses essais correspondants.

votre structure de projet peut ressembler à ceci: -

Project/
|-- pom.xml/
|
|-- src/
|   |-- test/
|   |   |-- com.acme.project
|   |   |        |-- com/acme/project
|   |   |        |      |-- SomeTest.java
|   |   
|   |-- main/
|   |   |-- com.acme.project
|   |   |    |-- module-info.java
|   |   |    |-- com/acme/project
|   |   |    |    |-- Main.java

module-info.java pourrait être:-

module com.acme.project {
    requires module1;
    requires module2;
    // requires junit; not required using Maven
}

juste pour résumer tout ce qui précède selon vos questions --

je sens que je suis le mauvais chemin, tout commence à sembler très laid. Comment puis-je avoir module-info.java de sa propre dans le code de test, ou comment atteindre l' mêmes effets (besoin, etc) sans elle?

Oui, vous ne devriez pas envisager la gestion de différents modules pour le code de test le rendant complexe.

vous pouvez obtenir un effet similaire en traitant junitau moment de la compilation de dépendance à l'aide des directives comme suit:

requires static junit;

en utilisant Maven vous pouvez réaliser ceci en suivant la structure indiquée ci-dessus et en utilisant maven-surefire-plugin qui assurerait la correction des tests au module par lui-même.

7
répondu nullpointer 2017-10-13 08:23:47

ajouter quelques détails.

en Java depuis 9, un fichier jar (ou un répertoire avec classes) peut être mis sur classpath (comme précédemment), ou sur le chemin du module. S'il est ajouté à classpath, son module-info est ignoré, et aucune restriction liée au module (ce qui lit quoi, ce qui exporte quoi, etc.) n'est appliquée. Si, cependant, un jar est ajouté à la trajectoire du module, il est traité comme un module, de sorte que son module-info est traité, et des restrictions supplémentaires liées au module seront imposé.

Dans mon cas, la ligne de commande, c'est comme le suivant:

/bin/sh -c cd /home/rpuch/git/my/test-java9-modules-junit && /home/rpuch/soft/jdk-9/bin/java --add-modules java.se.ee -jar /home/rpuch/git/my/test-java9-modules-junit/target/surefire/surefirebooter852849097737067355.jar /home/rpuch/git/my/test-java9-modules-junit/target/surefire 2017-10-12T23-09-21_577-jvmRun1 surefire8407763413259855828tmp surefire_05575863484264768860tmp

les classes sous test ne sont pas ajoutées en tant que module, donc elles sont sur classpath.

actuellement, un travail est en cours dans https://issues.apache.org/jira/browse/SUREFIRE-1262 (SUREFIRE-1420 est marqué comme un duplicata de SUREFIRE-1262) pour apprendre à surefire plugin à mettre le code à l'essai sur le chemin du module. Quand il est terminé et libéré, un module-info être pris en considération. Mais s'ils vont faire le module à l'essai pour lire le module junit automatiquement (comme SUREFIRE-1420 suggère), module-info (qui est un descripteur de module principal) ne devra pas inclure une référence à junit (qui est seulement nécessaire pour les tests).

un CV:

  1. module-info a juste besoin d'être ajouté aux principales sources
  2. pour le moment, surefire ignore nouveau module logique liée (mais cela va être modifié dans le futur)
  3. (lorsque les modules de travail en vertu de l'infaillible tests) junit n'aura probablement pas besoin d'être ajouté au module-info
  4. (quand les modules travail en vertu de l'infaillible tests) si un module est requis par les tests (et seulement par eux), il peut être ajouté comme une dépendance de compilation (en utilisant require static), comme suggéré par @nullpointer. Dans ce cas, le module Maven devra dépendre d'un artefact fournissant ce module de test seulement en utilisant la compilation (pas le test) scope que je n'aime pas beaucoup.
1
répondu Roman Puchkovskiy 2017-10-12 19:40:07