Utilizzo di Maven per creare file JAR separati per testare un'unità di un caricatore di classi personalizzato

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

Domanda

Come parte del mio progetto attuale ho creato un caricatore di classi personalizzato. Parte dei test unitari per il caricatore personalizzato prevede l'utilizzo di alcuni file JAR per dimostrare il comportamento corretto del caricatore.

Vorrei creare i file JAR di test da fonti Java prima di eseguire i test unitari effettivi. Inoltre, i file JAR di prova non possono trovarsi sul percorso di classe quando vengono eseguiti i test di unità, poiché desidero caricarli dinamicamente durante l'esecuzione del test.

Esiste un modello standard per realizzare questo tipo di "compilare alcuni JAR sul lato prima della fase di test ma lasciarli fuori dal percorso di classe" Requisiti? Non riesco a credere di essere la prima persona a provare a farlo con Maven 2, ma non riesco a trovare la giusta struttura e dipendenze POM. Di solito finisco con alcuni dei barattoli di test che non vengono creati prima della fase di test, ma ho anche avuto problemi con un incoerente ordine di costruzione che fa sì che la build funzioni correttamente su una macchina, ma non riesco a costruire alcuni dei testare vasetti su un altro.

È stato utile?

Soluzione

La cosa più semplice da fare è impostare un altro progetto per impacchettare le classi per il tuo vaso di prova, quindi impostarlo come un normale ambito test dipendenza.

Se non vuoi / non sei in grado di farlo, puoi usare il plugin assembly per creare un vaso nella fase process-test-classes (cioè dopo che i test sono stati compilato ma prima che i test vengano eseguiti). La configurazione seguente invocherà il plug-in di assembly per creare un vaso chiamato classloader-test-deps in quella fase nella directory di destinazione. I tuoi test possono quindi utilizzare quel vaso secondo necessità.

Il plugin assembly utilizza un descrittore assembly (in src / main / assembly, chiamato test-assembly.xml) che comprime i contenuti di target / classi di test. Ho impostato un filtro per includere i contenuti del pacchetto com.test e dei suoi figli. Ciò presuppone che tu abbia una convenzione sul nome del pacchetto che puoi applicare per il contenuto del vaso.

Per impostazione predefinita, il plug-in di assembly collegherà il vaso come artefatto aggiuntivo, specificando attach come falso, non verrà installato / distribuito.

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

Questo è il contenuto di 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>

Altri suggerimenti

Vorrei provare a impostare tutto ciò di cui i tuoi test hanno bisogno all'interno del test. Il vantaggio principale è che non esiste una configurazione invisibile magica implicita per il test. Il test può essere eseguito in ogni ambiente. Inoltre, è molto più semplice aggiungere nuovi scenari rigorosamente isolati poiché non si dipende da alcune impostazioni di scenari misti.

L'impostazione non dovrebbe essere troppo difficile:

  • serializzare una classe java:
    • con una libreria di ingegneria del codice di tipo
    • In alternativa, utilizzare un file di classe Java rinominato in un suffisso di file diverso da .class. Inseriscilo nella cartella delle risorse di test e caricalo con il programma di caricamento classi (getResourceAsStream (...)).
  • comprime il file di classe (`java.util.zip.GZIPOutputStream`)
  • carica il file di classe con il tuo caricatore di classe

Esiste un approccio alternativo che utilizza il design del caricatore di classi java e funziona senza generazione di classi aggiuntive.

Java ha una gerarchia di programmi di caricamento classi. Ogni programma di caricamento classe ha un programma di caricamento classe padre. La radice della gerarchia del programma di caricamento classe è il programma di caricamento classe di avvio. Quando una classe viene caricata con un programma di caricamento classi, proverà a caricare prima la classe con il programma di caricamento classi genitore e poi se stessa.

È possibile caricare la classe di test con il caricatore di classe corrente. Jar e caricarlo con il proprio caricatore di classe. L'unica differenza è che hai impostato il caricatore della classe genitore su uno che non è in grado di caricare la tua classe di test.

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 risolve l'ordine di compilazione tramite l'analisi delle dipendenze, quindi normalmente i tuoi JAR si comporterebbero in ordine perché quello che usa i JAR di test li dichiarerebbe semplicemente dipendenze. Tuttavia, le dipendenze vengono anche posizionate sul percorso di classe. Lo "scopo" di una dipendenza determina quale percorso di classe continua. Ad esempio, le dipendenze di "compilazione" si trovano sul percorso di classe per la compilazione, il test e l'esecuzione; le dipendenze 'runtime' sono sul percorso di classe per il test e l'esecuzione; Le dipendenze 'test' sono solo sul percorso di classe durante il test. Sfortunatamente, hai un caso non coperto da nessuno degli ambiti disponibili: hai una dipendenza, ma non la vuoi sul percorso di classe. Questo è un caso d'uso marginale ed è il motivo per cui hai problemi a scoprire esempi.

Quindi, a meno che qualche guru di Maven non si presenti per indicare il contrario, suggerisco che ciò sia impossibile senza scrivere uno speciale plugin Maven. Invece, consiglio comunque qualcos'altro. Hai davvero bisogno di JAR personalizzati per testare il tuo classloader? Mi sembra strano. Forse puoi usare qualsiasi vecchio JAR? In tal caso, utilizzerei il plug-in maven-dependency per copiare alcuni JAR noti per essere sempre nel vostro repository (ad esempio log4j) nella directory di destinazione del modulo locale. Il tuo test può quindi accedere a quel JAR tramite il percorso file in target / log4j-xxx.jar e puoi fare le tue cose.

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top