Правильная реализация модулей Java в сборке Maven с межмодульными тестовыми зависимостями - PullRequest
0 голосов
/ 26 ноября 2018

У меня есть многомодульный проект с использованием Maven и Java.Сейчас я пытаюсь перейти на Java 9/10/11 и внедрить модули (как в JSR 376: Система платформ Java , JPMS).Поскольку проект уже состоял из модулей Maven, а зависимости были прямыми, создание дескрипторов модулей для проекта было довольно простым.

Каждый модуль Maven теперь имеет свой собственный дескриптор модуля (module-info.java), вsrc/main/java папка.Для тестовых классов нет дескриптора модуля.

Однако я наткнулся на проблему, которую не смог решить, и не нашел описания того, как ее решить:

Как я могу иметь межмодульный проверить зависимости с модулями Maven и Java?

В моем случае у меня есть «общий» модуль Maven, который содержит некоторые интерфейсы и / или абстрактные классы (но без конкретной реализации).В том же модуле Maven у меня есть abstract тесты, чтобы гарантировать правильное поведение для реализации этих интерфейсов / абстрактных классов.Затем есть один или несколько подмодулей, с реализациями интерфейса / абстрактного класса и тестами, расширяющими абстрактный тест.

Однако при попытке выполнить фазу 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 и путем к модулю.

Ответы [ 2 ]

0 голосов
/ 11 апреля 2019

Я пытался сделать то же самое, невозможно иметь тесты whitebox и зависимости модуля test со структурой вашего проекта , но я думаю, что нашел альтернативную структуру, которая делает 90% от того, что выхочу сделать:

1 / Проблема с тестированием whitebox заключается в том, что он работает с исправлениями модулей, потому что JPMS не имеет понятия test main main в отличие от Maven.Так что это провоцирует проблемы, такие как не работа с тестовыми зависимостями или необходимость загрязнения информации о ваших модулях тестовыми зависимостями.

2 / Итак, почему бы не продолжать проводить тестирование белого ящика, но с maven структурой тестирования черного ящикато есть: разбить каждый модуль X на X и X-test.Только X имеет module-info.java, тесты выполняются в пути к классам, поэтому вы пропустите все эти проблемы.

Единственные недостатки, о которых я могу думать, это (в порядке возрастания важности):

  1. Что тестовая банка не будет модульной, но я думаю, что это приемлемо (по крайней мере дляnow).
  2. То, что у вас вдвое больше модулей maven, и вам может не понравиться разделять тесты в другом модуле maven.
  3. Тесты будут выполняться в пути к классам, и запускать всегда плохотесты в другой среде (тесты будут выполняться с меньшими ограничениями, чем основной код).Это может быть смягчено тестами дыма или специальным модулем интеграционных тестов?«Официальные паттерны» еще не появились.

Кстати (если это то, что вы делаете), я сомневаюсь, что оно стоит модульности, например.Приложение Spring Boot, так как сам Spring еще не является модульным, так что вы заплатите за него, но получите немного преимуществ (но если вы пишете библиотеку, это другая история).

Пример вы можете найти здесь:

a / Получить пример:

git clone https://github.com/vandekeiser/ddd-metamodel.git

git checkout stackoverflow

b / Посмотрите на пример:

  1. fr.cla.ddd.metamodel зависит от fr.cla.ddd.oo (но нет информации о модуле для тестов модулей maven)
  2. Я выполняю тестирование whitebox в PackagePrivateOoTest и в PackagePrivateMetamodelTest
  3. У меня есть тест-зависимость OoTestDependency
0 голосов
/ 06 декабря 2018

На основании вашего демонстрационного проекта я смог продублировать вашу ошибку.Тем не менее, вот пересмотренные изменения, которые я сделал после моей первой неудачной попытки, чтобы иметь возможность построить проект:

  1. Я добавил maven-compiler-plugin версию3.8.0 ко всем модулям.Вам нужна версия 3.7 или выше для компиляции модулей с Maven - по крайней мере, это предупреждение NetBeans.Поскольку вреда нет, я добавил плагин к файлам POM для общих и реализаций модулей:

    <plugin>
        <groupId>org.apache.maven.plugins</groupId>
        <artifactId>maven-compiler-plugin</artifactId>
        <version>3.8.0</version>
        <executions>
            <execution>
                <goals>
                    <goal>compile</goal>
                </goals>
                <id>compile</id>
            </execution>
        </executions>
    </plugin> 
    
  2. Я экспортировалтестовые классы в свой собственный файл jar, поэтому они будут доступны вашему модулю реализации или кому-либо в этом отношении.Для этого вам нужно добавить в ваш файл my-common-module/pom.xml следующее:

    <plugin>
        <groupId>org.apache.maven.plugins</groupId>
        <artifactId>maven-jar-plugin</artifactId>
        <version>3.1.0</version>
        <executions>
            <execution>
                <id>test-jar</id>
                <phase>package</phase>
                <goals>
                    <goal>test-jar</goal>
                </goals>
            </execution>
        </executions>
    </plugin>
    

    Это позволит экспортировать my-common-module тестовых классов в файл -tests.jar - т.е. my-common-module-1.0-SNAPSHOT-tests.jar.Обратите внимание, что нет необходимости добавлять выполнение для обычного jar файла, как отмечено в этом посте .Это, однако, будет связано с ошибкой, о которой я расскажу позже.

  3. Переименуйте ваш тестовый пакет в my-common-module в com.example.common.test, чтобы тестовые классы загружались при компиляции тестовых классов реализации.Это исправляет проблему загрузки классов, возникшую, когда мы экспортировали тестовые классы с тем же именем пакета, что и в модуле, где загружен первый jar, в данном случае модуль, а второй jar, файл jar теста,игнорируются.Интересно, что на основании наблюдения я заключаю, что путь к модулю имеет более высокий приоритет, чем путь к классу, поскольку параметры компиляции Maven показывают, что tests.jar указывается первым в пути к классам.Запустив mvn clean validate test -X, мы видим параметры компиляции:

    -d /home/testenv/NetBeansProjects/MavenProject/Implementation/target/test-classes -classpath /home/testenv/NetBeansProjects/MavenProject/Implementation/target/test-classes:/home/testenv/.m2/repository/com/example/Declaration/1.0-SNAPSHOT/Declaration-1.0-SNAPSHOT-tests.jar:/home/testenv/.m2/repository/junit/junit/4.12/junit-4.12.jar:/home/testenv/.m2/repository/org/hamcrest/hamcrest-core/1.3/hamcrest-core-1.3.jar: --module-path /home/testenv/NetBeansProjects/MavenProject/Implementation/target/classes:/home/testenv/.m2/repository/com/example/Declaration/1.0-SNAPSHOT/Declaration-1.0-SNAPSHOT.jar: -sourcepath /home/testenv/NetBeansProjects/MavenProject/Implementation/src/test/java:/home/testenv/NetBeansProjects/MavenProject/Implementation/target/generated-test-sources/test-annotations: -s /home/testenv/NetBeansProjects/MavenProject/Implementation/target/generated-test-sources/test-annotations -g -nowarn -target 11 -source 11 -encoding UTF-8 --patch-module example.implementation=/home/testenv/NetBeansProjects/MavenProject/Implementation/target/classes:/home/testenv/NetBeansProjects/MavenProject/Implementation/src/test/java:/home/testenv/NetBeansProjects/MavenProject/Implementation/target/generated-test-sources/test-annotations: --add-reads example.implementation=ALL-UNNAMED
    
  4. Нам нужно сделать экспортированные тестовые классы доступными для модуля реализации.Добавьте эту зависимость к вашему my-impl-module/pom.xml:

    <dependency>
        <groupId>com.example</groupId>
        <artifactId>Declaration</artifactId>
        <version>1.0-SNAPSHOT</version>
        <type>test-jar</type>
        <scope>test</scope>
    </dependency>
    
  5. Наконец в тестовом классе my-impl-module обновите импорт, чтобы указать новый тестовый пакет, com.example.common.text, чтобы получить доступ кmy-common-module тестовые классы:

    import com.example.declaration.test.AbstractFooTest;
    import com.example.declaration.Foo;
    import org.junit.Test;
    import static org.junit.Assert.*;
    
    /**
     * Test class inheriting from common module...
     */
    public class FooImplementationTest extends AbstractFooTest { ... }
    

Вот результаты теста из моих mvn clean package новых изменений:

enter image description here

Я обновил мой пример кода в своем java-cross-module-testing GitHub репо.Единственный нерешенный вопрос, который у меня есть, и я уверен, что вы тоже это делаете, заключается в том, почему он работал, когда я определил модуль реализации как обычный jar проект вместо модуля.Но я поиграю с другим днем.Надеюсь, то, что я предоставил, решит вашу проблему.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...