Using Maven to Create Separate JAR Files for Unit Testing a Custom Class Loader

As part of my current project, I created a custom class loader. Part of the unit tests for the user loader involves using some JAR files to demonstrate the correct behavior of the loader.

I would like to create test JAR files from Java sources before performing actual unit tests. In addition, test JAR files cannot be in the class path when performing unit tests, since I want to dynamically load them during test execution.

Is there a standard template for doing this kind of “building some JARs on the side before the testing phase, but rejecting the class requirement”? I cannot believe that I am the first person trying to do this with Maven 2, but I cannot get into the correct POM structure and dependencies. Usually I end up with some test banks not being created ahead of the testing phase, but I also had problems with an inconsistent assembly design that made the assembly work correctly on one machine, but failed to create some of the test banks on another.

+3
source share
3 answers

The simplest task is to create another project for packing classes for a test jar, and then set this up as a regular test-scoped dependency.

If you do not want / cannot do this, you can use the build plugin to create a flag in the process-test-classes phase (i.e., after the tests have been compiled, but before the tests are run). The configuration below will invoke the build plugin to create a jar named classloader-test-deps in this phase in the target directory. Then your tests can use this jar as needed.

The assembly plugin uses an assembly descriptor (in src / main / assembly, called test-assembly.xml), which packs the contents of the target / test classes. I set a filter to include the contents of the com.test package and its children. This assumes that you have a package name agreement that you can apply to the contents of the jar.

The build plugin will add the jar by default as an additional artifact, specifying attach as false, it will not be installed / deployed.

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

This is the contents of 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> 
+5
source

I would try to configure all your tests from a test. The main advantage is that there is no magical invisible setup that is implicit for the test. The test can work in any environment. In addition, it is much easier to add new strictly isolated scripts, since you are not dependent on any mixed script configuration.

Setup should not be too complicated:

  • serialize java class:
    • with a library of engineering code of a certain type
    • Alternatively, use a java class file renamed to some file suffix other than .class. Place it under the test resource folder and load the class loader (getResourceAsStream (...)).
  • zip class file (`java.util.zip.GZIPOutputStream`)
  • load the class file using the class loader

There is an alternative approach that uses the design of the java class loader and works without generating additional classes.

Java has a class loader hierarchy. Each class loader has a parent class loader. The root of the class loader hierarchy is the boot class loader. When a class is loaded by the class loader, it will try to load the class first using the parent class loader, and then itself.

You can load the test class from the current class loader. Fix it and load using your own class loader. The only difference is that you install the parent class loader to one that your test class cannot load.

 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(); 
+5
source

Maven allows build order through dependency analysis, so usually your JARs will be built in order, because the one that uses your test JARs will just declare them as dependencies. However, dependencies also apply to the classpath. The "scope" of a dependency determines which class it belongs to. For example, the dependencies of "compile" depend on the path to the classes for compilation, testing, and launch; The runtime dependencies are on the way to the class for testing and running; The 'test' dependencies apply only to the classpath during the test. Unfortunately, you have a case that is not covered by any of the available areas: you have a dependency, but you do not want this on the way to the classes. This is a random use case and therefore you are unable to find examples.

So, if only some Maven guru does not appear to point out the opposite, I believe that this is not possible without writing a special Maven plugin. However, I recommend something else instead. Do you really need specialized JARs to test your classloader? That sounds suspicious to me. Perhaps you can use any old JAR? If so, I would use the maven-dependency plugin to copy some JAR that was always in your repository (e.g. log4j) to your target directory of the local module. Then your test can access this JAR through the path to the target/log4j-xxx.jar , and you can do your job.

0
source

All Articles