Java 9 + maven + junit: нужен ли тестовый код module-info.java сама по себе и куда ее девать?

предположим, у меня есть проект Java с использованием Maven 3 и junit. Есть src/main/java и src/test/java справочники, которые содержат основные источники и испытаний, соответственно (все стандартно).

теперь я хочу перенести проект на Java 9. src/main/java содержимое представляет модуль Java 9; есть com/acme/project/module-info.java выглядит примерно так:

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

Что делать, если тестовый код должен module-info.java самостоятельно? Например, чтобы добавить зависимость от некоторого модуля, который только необходим для тестов, а не для производственного кода. В таком случае, я должен поставить module-info.java to src/test/java/com/acme/project/ присвоение модулю другого имени. Таким образом, Maven, похоже, рассматривает основные источники и тестовые источники как разные модули, поэтому я должен экспортировать пакеты из основного модуля в тестовый модуль и требовать пакеты в тестовом модуле, что-то вроде этого:

главный модуль (в src/main/java/com/acme/project):

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

модуль тестирования (в src/test/java/com/acme/project):

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

этот производит

[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

потому что один пакет определен в двух модулях. Поэтому теперь у меня должны быть разные проекты в основном модуле и тестовом модуле, что не удобно.

я чувствую, что иду неправильным путем, все это начинает выглядеть очень уродливо. Как я могу иметь module-info.java в тестовый код, или как я могу достичь тех же эффектов (require и т. д.) без него?

3 ответов


система модуля не различает между кодом продукции и кодом теста, поэтому если вы выбираете modularize код теста, то prod.module и test.module нельзя использовать один и тот же пакет com.acme.project, как описано в технические характеристики:

невмешательство - компилятор Java, виртуальная машина и система времени выполнения должны гарантировать, что модули, содержащие пакеты с одинаковыми именами, не мешают друг другу. Если два отдельных модуля содержат пакеты с тем же именем, с точки зрения каждого модуля, все типы и члены в этом пакете определяются только этим модулем. Код в этом пакете в одном модуле не должен иметь доступа к пакетам-частным типам или членам в этом пакете в другом модуле.

как указано Аланом Бейтменом, плагин компилятора Maven использует --patch-module и другие опции предоставлено системой модулей при компиляции кода в дереве src/test/java, поэтому что тестируемый модуль дополняется тестовыми классами. И это также делается плагином Surefire при запуске тестовых классов (см. поддержка запуска модульных тестов в именованных модулях Java 9). Это означает, что вам не нужно размещать тестовый код в модуле.


вы хотите переосмыслите дизайн проекта, который вы пытаетесь реализовать. Поскольку вы внедряете модуль и его тестирование в проект, вы должны воздерживаться от использования различных модулей для каждого из них индивидуально.

должен быть только одинmodule-info.java для модуля и его соответствующих тестов.

соответствующие структура проекта может выглядеть следующим образом:-

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 может быть:-

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

просто подытожить все вышесказанное в соответствии с вашими вопросами -

Я чувствую, что иду неправильным путем, все это начинает выглядеть очень уродливо. Как я могу есть модуль-инфо.java самостоятельно в тестовом коде, или как я могу достичь те же эффекты (требуют и т. д.) без него?

да, вы не должны рассматривать управление различными модулями для тестирования кода, что делает его сложным.

вы можете добиться подобного эффекта путем обработки junit как времени компиляции зависимостей используя директивы следующим образом -

requires static junit;

используя Maven, вы можете достичь этого, следуя вышеуказанной структуре и используя maven-surefire-plugin который позаботится о исправлении тестов к модулю сам по себе.


добавление некоторых деталей.

в Java, начиная с 9, файл jar (или каталог с классами) может быть помещен в classpath (как и ранее) или в путь модуля. Если он добавлен в classpath, его информация о модуле игнорируется, и никакие ограничения, связанные с модулем (что читает, что экспортирует и т. д.), не применяются. Если, однако, jar добавляется к пути модуля, он рассматривается как модуль, поэтому его информация о модуле обрабатывается, и дополнительные ограничения, связанные с модулем, будут принужденный.

В настоящее время (версия 2.20.1) maven-surefire-plugin может работать только по-старому, поэтому он помещает классы, тестируемые на classpath, а module-path игнорируется. Итак, прямо сейчас добавление module-info в проект Maven не должно ничего менять при запуске тестов с использованием Maven (с плагином surefire).

в моем случае командная строка выглядит следующим образом:

/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

тестируемые классы не добавляются в качестве модуля, поэтому они включены путь класса.

В настоящее время ведется работа в https://issues.apache.org/jira/browse/SUREFIRE-1262 (SUREFIRE-1420 помечен как дубликат SUREFIRE-1262), чтобы научить плагин surefire тестировать код на пути модуля. Когда он будет завершен и выпущен, модуль-info будет считаться. Но если они сделают тестируемый модуль для автоматического чтения модуля junit (как предлагает SUREFIRE-1420), module-info (который является основным дескриптором модуля) не нужно будет включать ссылку на junit (которая необходима только для тестов).

резюме:

  1. модуль-информация просто должна быть добавлена к основной источник
  2. в настоящее время surefire игнорирует новую логику, связанную с модулем (но это будет изменено в будущем)
  3. (когда модули будут работать под верный тесты) junit, вероятно, не нужно будет добавлять в модуль-info
  4. (когда модули будет работать при верных испытаниях) если какой-то модуль требуется тестами (и только ими), он может быть добавлен как зависимость только от компиляции (используя require static), как предложил @nullpointer. В этом случае модуль Maven должен будет зависеть от артефакта, поставляющего этот тестовый модуль, используя область компиляции (не тест), которая мне не очень нравится.