2017-10-06 6 views
14

Disons que j'ai un projet Java utilisant Maven 3 et junit. Il existe des répertoires src/main/java et src/test/java qui contiennent respectivement les sources principales et les sources de test (tout est standard).Java 9 + maven + junit: est-ce que le code de test a besoin de module-info.java de son côté et où le mettre?

Maintenant, je souhaite migrer le projet vers Java 9. Le contenu src/main/java représente le module Java 9; il est à la recherche d'environ com/acme/project/module-info.java comme ceci:

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

si le code de test doit module-info.java de son propre? Par exemple, pour ajouter une dépendance à un module qui est seulement nécessaire pour les tests, pas pour le code de production. Dans un tel cas, je dois mettre module-info.java à src/test/java/com/acme/project/ en donnant 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 exiger des paquets dans le module de test:

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

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

module de test (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 

car un package est défini dans 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 un mauvais chemin, tout commence à avoir l'air très moche. Comment puis-je avoir module-info.java de son propre dans le code de test, ou comment puis-je obtenir les mêmes effets (require, etc) sans elle?

+0

D'abord oublier Maven 2 ... utiliser Maven 3 + ... un 'module-info' dans le test est-ce que de mon point de vue cela n'a pas de sens? Exigence spéciale/réalisation derrière cela? – khmarbaise

+0

C'est Maven 3, bien sûr –

Répondre

4

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

Non-interférence - Le compilateur Java, la machine virtuelle et le système d'exécution doivent s'assurer que les modules contenant des packages du même nom n'interfèrent pas entre eux. Si deux modules distincts contiennent des 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 de ce module dans un module ne doit pas pouvoir accéder aux types ou aux membres de package privé dans ce module dans l'autre module.

Comme indiqué par Alan Bateman, le plugin compilateur Maven utilise --patch-module and other options fourni par le système de module lors de la compilation du code dans l'arbre src/test/java, de sorte que le module sous test est augmentée avec les classes de test. Et ceci est également fait par le plugin Surefire lors de l'exécution des classes de test (voir Support running unit tests in named Java 9 modules). Cela signifie que vous n'avez pas besoin de placer votre code de test dans un module.

+1

La modification du package à tester présente l'inconvénient que vos tests n'atteindront plus les modificateurs par défaut et protégés. –

+1

Le module fournit --patch-module et d'autres options pour prendre en charge la compilation et l'exécution des tests qui se trouvent dans le même module/module que le module testé. Le maven-compiler-plugin utilise ces options lors de la compilation de code dans l'arborescence src/test. Idem pour le plugin surefire. –

+0

@AlanBateman Merci pour cette info. Je ne savais pas que Maven le faisait. Je vais mettre à jour la réponse avec vos informations. – manouti

7

Vous voudrez peut-être repenser la conception du projet que vous essayez d'implémenter. Puisque vous implémentez un module et son test dans un projet, vous devez vous abstenir d'utiliser différents modules pour chacun d'entre eux individuellement.

Il devrait juste être un seul module-info.java pour un module et ses tests correspondants.

Votre structure de projet pertinent pourrait 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 

où le plus module-info.java pourrait être: -

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

Pour résumer tous les ci-dessus par votre questions -

Je sens que je suis un mauvais chemin, tout commence à avoir l'air très moche. Comment puis-je avoir module-info.java de son propre dans le code de test, ou comment puis-je obtenir le mêmes effets (exiger, etc) sans elle?

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

Vous pouvez obtenir un effet similaire en traitant junit comme compile-time dependency en utilisant les directives ci-dessous- comme

requires static junit; 

En utilisant Maven, vous pouvez obtenir ce qui suit la structure indiquée ci-dessus et en utilisant maven-surefire-plugin qui prendrait soin de patcher les tests sur le module par lui-même.

+0

Je suggérerais de ne pas utiliser un nom de module dans la structure du répertoire car il n'y a aucun avantage dedans ....? – khmarbaise

+0

@khmarbaise Je crois que vous voulez dire le 'com.acme.project/com/acme/project'. Juste suivi le [guide de démarrage rapide] (http://openjdk.java.net/projects/jigsaw/quick-start) là. Bien que je sois d'accord, cela ne procure aucun avantage en tant que tel. – nullpointer

+1

Exiger 'junit' dans le descripteur de module ne semble pas très bien pour moi – ZhekaKozlov

1

Ajout de quelques détails.

En Java depuis 9, un fichier jar (ou un répertoire avec classes) peut être placé sur classpath (comme précédemment), ou sur le chemin du module. Si elle est ajoutée à 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, toutefois, un jar est ajouté au chemin du module, il est traité comme un module, de sorte que son module-info est traité et que des restrictions supplémentaires liées au module seront appliquées.

Actuellement (version 2.20.1), maven-surefire-plugin ne peut fonctionner que de la manière habituelle, donc il place les classes testées sur classpath, et module-path est ignoré. Donc, en ce moment, l'ajout de module-info à un projet Maven ne devrait rien changer aux tests exécutés avec Maven (avec le plugin surefire).

Dans mon cas, la ligne de commande est comme ce qui suit:

/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 en cours de test ne sont pas ajoutées en tant que module, ils sont sur classpath.

Actuellement, un travail est en cours dans https://issues.apache.org/jira/browse/SUREFIRE-1262 (SUREFIRE-1420 est marqué comme un doublon de SUREFIRE-1262) pour enseigner au plugin surefire de mettre du code sous test sur le chemin du module. Quand il est terminé et libéré, un module-info sera considéré.Mais s'ils font tester le module pour lire le module junit automatiquement (comme le suggère SUREFIRE-1420), 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 curriculum vitae:

    module d'info
  1. a juste besoin d'être ajouté aux sources principales
  2. pour le moment, surefire ne tient pas nouvelle logique liée module (mais cela sera changé dans l'avenir)
  3. (lorsque les modules fonctionneront sous des tests infaillibles) JUnit ne sera probablement pas nécessaire d'ajouter au module-info
  4. (lorsque les modules fonctionneront sous des tests infaillibles) si un module est requis par les tests (et seulement par eux), il peut être ajouté en tant que dépendance de compilation uniquement (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 portée de compilation (pas de test) que je n'aime pas beaucoup.