У меня есть многомодульный проект с использованием Maven и Java. Сейчас я пытаюсь перейти на Java 9/10/11 и реализовать модули (как в JSR 376: Java Platform Module System, JPMS). Поскольку проект уже состоял из модулей Maven, а зависимости были прямыми, создание дескрипторов модулей для проекта было довольно простым.
Каждый модуль Maven теперь имеет свой собственный дескриптор модуля (module-info.java
) в папке src/main/java
. Для тестовых классов нет дескриптора модуля.
Однако я наткнулся на проблему, которую не смог решить, и не нашел описания того, как ее решить:
Как я могу иметь межмодульные тестовые зависимости с модулями Maven и Java?
В моем случае у меня есть "общий" модуль Maven, который содержит некоторые интерфейсы и/или абстрактные классы (но без конкретной реализации). В том же модуле Maven у меня есть абстрактные тесты, чтобы гарантировать правильное поведение для реализации этих интерфейсов/абстрактных классов. Затем есть один или несколько подмодулей с реализациями интерфейса/абстрактного класса и тестами, расширяющими абстрактный тест.
Тем не менее, при попытке выполнить test
фазу сборки Maven, подмодуль завершится неудачно с:
[ERROR] Failed to execute goal org.apache.maven.plugins:maven-compiler-plugin:3.8.0:testCompile (default-testCompile) on project my-impl-module: Compilation failure: Compilation failure:
[ERROR] C:\projects\com.example\my-module-test\my-impl-module\src\test\java\com\example\impl\FooImplTest.java:[4,25] error: cannot find symbol
[ERROR] symbol: class FooAbstractTest
[ERROR] location: package com.example.common
Я подозреваю, что это происходит потому, что тесты не являются частью модуля. И даже если Maven совершает "магию" для выполнения тестов в рамках модуля, он не работает для тестов в модуле, от которого я зависел (по какой-то причине). Как это исправить?
Структура проекта выглядит следующим образом (полные файлы демонстрационных проектов доступны здесь):
├───my-common-module
│ ├───pom.xml
│ └───src
│ ├───main
│ │ └───java
│ │ ├───com
│ │ │ └───example
│ │ │ └───common
│ │ │ ├───AbstractFoo.java (abstract, implements Foo)
│ │ │ └───Foo.java (interface)
│ │ └───module-info.java (my.common.module: exports com.example.common)
│ └───test
│ └───java
│ └───com
│ └───example
│ └───common
│ └───FooAbstractTest.java (abstract class, tests Foo)
├───my-impl-module
│ ├───pom.xml
│ └───src
│ ├───main
│ │ └───java
│ │ ├───com
│ │ │ └───example
│ │ │ └───impl
│ │ │ └───FooImpl.java (extends AbstractFoo)
│ │ └───module-info.java (my.impl.module: requires my.common.module)
│ └───test
│ └───java
│ └───com
│ └───example
│ └───impl
│ └───FooImplTest.java (extends FooAbstractTest)
└───pom.xml
Зависимости в my-impl-module/pom.xml
следующие:
<dependencies>
<dependency>
<groupId>com.example</groupId>
<artifactId>my-common-module</artifactId>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>com.example</groupId>
<artifactId>my-common-module</artifactId>
<classifier>tests</classifier> <!-- tried type:test-jar instead, same error -->
<scope>test</scope>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
Примечание. Выше приведен только проект, который я создал для демонстрации проблемы. Реальный проект намного сложнее, и его можно найти здесь (основная ветвь еще не модульная), но принцип тот же.
PS: я не думаю, что что-то не так с самим кодом, так как все компилируется и выполняется с использованием обычного пути к классам (то есть в IntelliJ или Maven без дескрипторов модулей Java). Проблема вводится с модулями Java и путем к модулю.