proyecto programacion modulos modularidad implementacion generar ejemplos declaracion crear como aplica java maven junit module java-9
archivos de proyecto de demostración completos disponibles aquí

programacion - modularidad en java ejemplos



Implementación adecuada de módulos Java en una compilación Maven con dependencias de prueba entre módulos (1)

Tengo un proyecto multi-modulo usando Maven y Java. Ahora estoy intentando migrar a Java 9/10/11 e implementar módulos (como en JSR 376: Java Platform Module System , JPMS). Como el proyecto ya consistía en módulos de Maven y las dependencias eran directas, la creación de descriptores de módulo para el proyecto era bastante sencilla.

Cada módulo de Maven ahora tiene su propio descriptor de módulo ( module-info.java ), en la carpeta src/main/java . No hay descriptor de módulo para las clases de prueba.

Sin embargo, me topé con un problema que no he podido resolver y no he encontrado ninguna descripción sobre cómo resolverlo:

¿Cómo puedo tener dependencias de prueba entre módulos con los módulos de Maven y Java?

En mi caso, tengo un módulo Maven "común", que contiene algunas interfaces y / o clases abstractas (pero ninguna implementación concreta). En el mismo módulo de Maven, tengo pruebas abstractas para garantizar el comportamiento adecuado para la implementación de estas interfaces / clases abstractas. Luego, hay uno o más submódulos, con implementaciones de la clase interface / abstract y pruebas que extienden la prueba abstracta.

Sin embargo, al intentar ejecutar la fase de test de la compilación de Maven, el módulo secundario fallará con:

[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

Sospecho que esto sucede porque las pruebas no forman parte del módulo . E incluso si Maven hace algo de "magia" para que las pruebas se ejecuten dentro del alcance del módulo, no funciona para las pruebas en el módulo del que dependo (por alguna razón). ¿Cómo puedo solucionar esto?

La estructura del proyecto tiene este aspecto ( archivos de proyecto de demostración completos disponibles aquí ):

├───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

Las dependencias en my-impl-module/pom.xml son las siguientes:

<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>

Nota: Lo anterior es solo un proyecto que creé para demostrar el problema. El proyecto real es mucho más complejo, y se encuentra aquí (la rama principal aún no está modularizada), pero el principio es el mismo.

PD: No creo que haya nada malo con el código en sí, ya que todo se compila y ejecuta utilizando la ruta de clase normal (es decir, en IntelliJ o Maven sin los descriptores de módulo de Java). El problema se introduce con los módulos de Java y la ruta del módulo.


Basado en su proyecto de demostración, pude duplicar su error. Dicho esto, aquí están los cambios revisados que hice, después de mi primer intento fallido, para poder construir el proyecto:

  1. Agregué la versión 3.8.0 de maven-compiler-plugin a todos los módulos. Necesita una versión de 3.7 o superior para compilar módulos con Maven, al menos esa es la advertencia que mostró NetBeans. Como no hay ningún daño, agregué el complemento a los archivos POM comunes y de los módulos de implementación :

    <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. Exporté las clases de prueba a su propio archivo jar para que estén disponibles para su módulo de implementación o para cualquiera. Para hacerlo, debe agregar lo siguiente a su archivo 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>

    Esto exportará las clases de prueba de my-common-module al archivo -tests.jar , es decir, my-common-module-1.0-SNAPSHOT-tests.jar . Tenga en cuenta que no es necesario agregar una ejecución para el archivo jar normal como se indica en esta post . Esto, sin embargo, introdujo el error que abordaré a continuación.

  3. Cambie el nombre de su paquete de prueba en my-common-module a com.example.common.test para que las clases de prueba se carguen al compilar la (s) clase (s) de prueba de implementación. Esto corrige el problema de carga de clases que se introdujo cuando exportamos las clases de prueba con el mismo nombre de paquete que en el módulo donde se carga el primer archivo jar , en este caso el módulo, y se ignora el segundo archivo jar, el archivo jar de prueba. Lo suficientemente interesante, estoy concluyendo, en base a la observación, que la ruta del módulo tiene mayor prioridad que la ruta de la clase, ya que los parámetros de compilación de Maven muestran que tests.jar se especifica primero en la ruta de la clase. Al ejecutar mvn clean validate test -X , vemos los parámetros de compilación:

    -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. Necesitamos que las clases de prueba exportadas estén disponibles para el módulo de implementación. Agregue esta dependencia a su 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. Por último, en la clase de prueba my-impl-module , actualice la importación para especificar el nuevo paquete de prueba, com.example.common.text , para acceder a las clases de prueba 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 { ... }

Aquí están los resultados de las pruebas de mi mvn clean package de los nuevos cambios:

Actualicé mi código de muestra en el repositorio de GitHub de java-cross-module-testing . La única pregunta persistente que tengo, y estoy seguro de que usted también lo hace, es por qué funcionó cuando definí el módulo de implementación como un proyecto jar normal en lugar de un módulo. Pero eso, jugaré con algún otro día. Esperemos que lo que proporcioné resuelva tu problema.