Подтвердить что ты не робот

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 в 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 и т.д.) Без него?

4b9b3361

Ответ 1

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

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

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

Ответ 2

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

Для модуля и его соответствующих тестов должен быть только один 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
}

Просто суммируйте все вышеперечисленное по вашим вопросам -

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

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

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

requires static junit;

Забастовкa >

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

Ответ 3

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

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

В настоящее время (версия 2.20.1), maven-surefire-plugin может работать только по-старому, поэтому он ставит тестируемые классы в classpath, а модуль-путь игнорируется. Итак, прямо сейчас добавление модуля-информации в проект 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 . Но если они будут проверять модуль, чтобы он автоматически считывал модуль юнита (как предполагает SUREFIRE-1420), модуль-информация (которая является основным дескриптором модуля) не должна включать ссылку на junit (которая нужна только для тестов).

резюме:

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