Java >> Java tutorial >  >> Tag >> java.lang

Java.lang.NoClassDefFoundError i JUnit

1. Oversigt

I denne artikel vil vi forstå, hvorfor java.lang.NoClassDefFoundError opstår i JUnit, og hvordan man løser det. Dette problem er hovedsageligt relateret til IDE's konfigurationer. Derfor vil vi fokusere på de mest populære IDE'er:Visual Studio Code, Eclipse og IntelliJ for at reproducere og løse denne fejl.

2. Hvad er java.lang.NoClassDefFoundError ?

Når Java Runtime kører et Java-program, indlæser det ikke alle klasser og afhængigheder på én gang. I stedet opfordrer den Java Classloader til at indlæse klasser i hukommelsen efter behov. Under indlæsning af en klasse, hvis Classloader ikke kan finde klassens definition, kaster den  NoClassDefFoundError .

Der er et par grunde til, at Java ikke kan finde klassens definition, som er:

  • Mangler et par afhængige krukker, hvilket er den mest almindelige årsag.
  • Alle jars tilføjes som afhængigheder, men på den forkerte vej.
  • Version stemmer ikke overens i afhængighederne.

3. VS-kode

For at skrive Junit4-testcases kræver vi Junit4-krukken. Imidlertid har Junit4 en intern afhængighed af hamcrest-kernen krukke.

Hvis vi savner at tilføje hamcrest-kernen jar som en afhængighed i vores klassesti, kaster Java NoClassDefFoundError . Klassestien er som følger:

Et andet scenarie er, når vi tilføjede begge krukkerne, men versioner stemmer ikke overens. For eksempel, hvis vi har tilføjet JUnit jar version 4.13.2 og hamcrest-kernen jar version 2.2, NoClassDefFoundError er kastet:

I begge tilfælde udskrives det samme stakspor:

java.lang.NoClassDefFoundError: org/hamcrest/SelfDescribing
	at java.base/java.lang.ClassLoader.defineClass1(Native Method)
	at java.base/java.lang.ClassLoader.defineClass(ClassLoader.java:1010)
	at java.base/java.security.SecureClassLoader.defineClass(SecureClassLoader.java:150)
	at java.base/jdk.internal.loader.BuiltinClassLoader.defineClass(BuiltinClassLoader.java:855)
	at java.base/jdk.internal.loader.BuiltinClassLoader.findClassOnClassPathOrNull(BuiltinClassLoader.java:753)
	at java.base/jdk.internal.loader.BuiltinClassLoader.loadClassOrNull(BuiltinClassLoader.java:676) ...

For at løse fejlen i begge scenarier (manglende afhængigheder og versionsuoverensstemmelse), skal vi tilføje de korrekte afhængigheder. De korrekte afhængigheder i tilfælde af Junit4 er junit-4.13.2.jar og hamcrest-core-1.3.jar . Tilføjelse af disse to krukker i afhængighederne (Referenced Libraries) løser fejlen. Instruktionerne til at tilføje og fjerne eksterne krukker i VS Code er til stede her. Vores refererede bibliotekssektion skal sættes op som:

4. Formørkelse

I Eclipse IDE, der understøtter Java 9 og nyere, har vi en klassesti og en modulsti. For at løse modulafhængighed bruger vi modulstien. Men tilføjelse af eksterne krukker i modulstien gør dem ikke tilgængelige for klasseindlæseren . Derfor betragter klasseindlæseren dem som manglende afhængigheder og kaster NoClassDefFoundError .

Derfor, hvis vores afhængighed ser ud som nedenstående billede, vil kørsel af en Junit-testsag resultere i en NoClassDefFoundError:

Staksporet, der genereres ved kørsel af JUnit-testen, er:

java.lang.NoClassDefFoundError: org/junit/runner/manipulation/Filter
	at java.base/java.lang.Class.forName0(Native Method)
	at java.base/java.lang.Class.forName(Class.java:377)
	at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.loadTestLoaderClass(RemoteTestRunner.java:381)

I Eclipse skal vi tilføje krukkerne under klassestien og ikke i modulstien. Så for at tilføje eksterne krukker korrekt, følg stien:

højreklik på Projekt -> Byg sti -> Konfigurer byggesti

I det vindue, der åbnes, skal du fjerne krukkerne fra under modulstien og tilføje dem under klassestien. Dette løser NoClassDefFoundError . Den korrekte klassesti til at køre JUnit bør ligne:

5. IntelliJ

Kørsel af JUnit 5-testcases kræver både Jupiter-motoren og Jupiter API. Jupiter-motoren er internt afhængig af Jupiter API, og derfor er det det meste af tiden tilstrækkeligt kun at tilføje Jupiter-motorafhængigheden i pom.xml. Tilføjelse af kun Jupiter API-afhængigheden i vores pom.xml og manglende Jupiter-motorafhængighed resulterer i NoClassDefFoundError .

Den forkerte opsætning i pom.xml ville være sådan her:

<dependencies>
    <dependency>
        <groupId>org.junit.jupiter</groupId>
        <artifactId>junit-jupiter-api</artifactId>
        <version>5.8.1</version>
        <scope>test</scope>
    </dependency>
</dependencies>

Kørsel af en simpel testcase med denne opsætning resulterer i følgende staksporing:

Exception in thread "main" java.lang.NoClassDefFoundError: org/junit/platform/engine/TestDescriptor
	at java.base/java.lang.Class.forName0(Native Method)
	at java.base/java.lang.Class.forName(Class.java:375)
	at com.intellij.rt.junit.JUnitStarter.getAgentClass(JUnitStarter.java:230)
....

For at rette afhængighederne i IntelliJ skal vi rette pom.xml . Den rettede pom.xml ser sådan ud:

<dependencies>
    <dependency>
        <groupId>org.junit.jupiter</groupId>
        <artifactId>junit-jupiter-api</artifactId>
        <version>5.8.1</version>
        <scope>test</scope>
    </dependency>
    <dependency>
        <groupId>org.junit.jupiter</groupId>
        <artifactId>junit-jupiter-engine</artifactId>
        <version>5.8.1</version>
        <scope>test</scope>
    </dependency>
</dependencies>

Alternativt kan vi tilføje junit-jupiter-motor da tilføjelse af det automatisk tilføjer junit-jupiter-api jar til klassestien og løser fejlen.

6. Resumé

I denne artikel så vi forskellige årsager til java.lang.NoClassDefFoundError at forekomme i JUnit. Vi så også, hvordan vi løser fejlen i forskellige IDE'er. Hele koden til denne tutorial er tilgængelig på GitHub.


Java tag