Usando Maven para construir archivos JAR separados para pruebas unitarias de un cargador de clases personalizado

StackOverflow https://stackoverflow.com/questions/1401857

Pregunta

Como parte de mi proyecto actual, he creado un cargador de clases personalizado. Parte de las pruebas unitarias para el cargador personalizado implica el uso de algunos archivos JAR para demostrar el comportamiento correcto del cargador.

Me gustaría compilar los archivos JAR de prueba a partir de fuentes Java antes de ejecutar las pruebas unitarias reales. Además, los archivos JAR de prueba no pueden estar en la ruta de clase cuando se ejecutan las pruebas unitarias, ya que quiero cargarlas dinámicamente durante la ejecución de la prueba.

¿Existe un patrón estándar para realizar este tipo de " compilar algunos JAR en el lado antes de la fase de prueba pero dejarlos fuera de la ruta de clase " ¿requisito? No puedo creer que sea la primera persona que intente hacer esto con Maven 2, pero parece que no puedo encontrar la estructura y dependencias correctas de POM. Por lo general, termino con algunos de los frascos de prueba que no se construyen antes de la fase de prueba, pero también he tenido problemas con un orden de construcción inconsistente que hace que la construcción funcione correctamente en una máquina, pero no puedo construir algunos de los probar frascos en otro.

¿Fue útil?

Solución

Lo más sencillo es configurar otro proyecto para empaquetar las clases para su prueba jar, luego establecerlo como normal test-scoped dependency.

Si no desea / no puede hacer eso, puede usar el complemento de ensamblaje para crear un contenedor en la fase proceso-prueba-clases (es decir, después de que las pruebas hayan sido compilado pero antes de que se ejecuten las pruebas). La siguiente configuración invocará el complemento de ensamblaje para crear un archivo llamado classloader-test-deps en esa fase en el directorio de destino. Tus pruebas pueden usar ese frasco según sea necesario.

El complemento de ensamblaje utiliza un descriptor de ensamblaje (en src / main / assembly, llamado test-assembly.xml) que empaqueta los contenidos de target / test-classes. He configurado un filtro para incluir el contenido del paquete com.test y sus hijos. Esto supone que tiene alguna convención de nombre de paquete que puede solicitar para el contenido del contenedor.

El complemento de ensamblaje adjuntará de forma predeterminada el archivo jar como un artefacto adicional, especificando attach como falso, no se instalará / desplegará.

<plugin>
  <artifactId>maven-assembly-plugin</artifactId>
  <version>2.2-beta-2</version>
  <executions>
    <execution>
      <id>create-test-dependency</id>
      <phase>process-test-classes</phase>
      <goals>
        <goal>single</goal>
      </goals>
      <configuration>
        <finalName>classloader-test-deps</finalName>
        <attach>false</attach>
        <descriptors>
          <descriptor>src/main/assembly/test-assembly.xml</descriptor>
        </descriptors>
      </configuration>
    </execution>
  </executions>
</plugin>

Este es el contenido de test-assembly.xml

<assembly>
  <id>test-classloader</id>
  <formats>
    <format>jar</format>
  </formats>
  <includeBaseDirectory>false</includeBaseDirectory>
  <fileSets>
    <fileSet>
      <directory>${project.build.testOutputDirectory}</directory>
      <outputDirectory>/</outputDirectory>
      <!--modify/add include to match your package(s) -->
      <includes>
        <include>com/test/**</include>
      </includes>
    </fileSet>
  </fileSets>
</assembly>

Otros consejos

Intentaría configurar todo lo que sus pruebas necesitan dentro de la prueba. La principal ventaja es que no hay una configuración mágica invisible que esté implícita para la prueba. La prueba puede ejecutarse en cualquier entorno. Además, es mucho más fácil agregar nuevos escenarios estrictamente aislados, ya que no depende de una configuración de escenarios mixtos.

La configuración no debería ser demasiado difícil:

  • serializar una clase java:
    • con alguna biblioteca de ingeniería de código de tipo
    • Alternativamente, use un archivo de clase java renombrado a algún sufijo de archivo que no sea .class. Colóquelo en la carpeta de recursos de prueba y cárguelo con el cargador de clases (getResourceAsStream (...)).
  • comprimir el archivo de clase (`java.util.zip.GZIPOutputStream`)
  • cargue el archivo de clase con su cargador de clases

Existe un enfoque alternativo que utiliza el diseño del cargador de clases de Java y funciona sin generar clases adicionales.

Java tiene una jerarquía de carga de clases. Cada cargador de clases tiene un cargador de clases padre. La raíz de la jerarquía del cargador de clases es el cargador de clases de arranque. Cuando una clase se carga con un cargador de clases, intentará cargar la clase primero con el cargador de clases padre y luego con ella misma.

Puede cargar la clase de prueba con el cargador de clases actual. Llévelo y cárguelo con su propio cargador de clases. La única diferencia es que configura el cargador de clases principal en uno que no pueda cargar su clase de prueba.

String resource = My.class.getName().replace(".", "/") + ".class";

//class loader of your test class
ClassLoader myClassLoader = currentThread().getContextClassLoader();
assert ! toList(myClassLoader.getResources(resource)).isEmpty();

//just to be sure that the resource cannot be loaded from the parent classloader
ClassLoader parentClassloader = getSystemClassLoader().getParent();
assert toList(parentClassloader.getResources(resource)).isEmpty();

//your class loader
URLClassLoader myLoader = new URLClassLoader(new URL[0], parentClassloader);
assert toList(myLoader.getResources(resource)).isEmpty();

Maven resuelve el orden de compilación a través del análisis de dependencia, por lo que normalmente sus JAR se construirían en orden porque el que usa sus JAR de prueba simplemente los declararía como dependencias. Sin embargo, las dependencias también se colocan en el classpath. El " alcance " de una dependencia determina qué classpath continúa. Por ejemplo, las dependencias de "compilación" están en la ruta de clase para compilar, probar y ejecutar; Las dependencias de 'tiempo de ejecución' están en la ruta de clase para probar y ejecutar; Las dependencias de 'prueba' solo están en el classpath durante la prueba. Desafortunadamente, tiene un caso que no está cubierto por ninguno de los ámbitos disponibles: tiene una dependencia, pero no la quiere en la ruta de clase. Este es un caso de uso marginal y es por eso que tiene problemas para descubrir ejemplos.

Entonces, a menos que algún gurú de Maven se levante para indicar lo contrario, sugiero que esto es imposible sin escribir un complemento especial de Maven. En lugar de eso, sin embargo, recomiendo algo más. ¿Realmente necesitas JAR personalizados para probar tu cargador de clases? Eso me suena a pescado. Tal vez puedas usar algún JAR viejo? Si es así, usaría el complemento de dependencia de maven para copiar algunos JAR que se sabe que siempre están en su repositorio (log4j, por ejemplo) en el directorio de destino de su módulo local. Su prueba puede acceder a ese JAR a través de la ruta de archivo en target / log4j-xxx.jar y usted puede hacer lo suyo.

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top