2013-05-13 10 views
86

Ich habe einen solchen Code-Schnipsel bekam:Mockito + PowerMock LinkageError während spöttischen Systemklasse

@RunWith(PowerMockRunner.class) 
@PrepareForTest({Thread.class}) 
public class AllMeasuresDataTest { 

@Before 
public void setUp() throws Exception { 
} 

@Test 
public void testGetMeasures() { 
    AllMeasuresData measure = new AllMeasuresData(); 
    assertEquals(measure.getMeasures(), null); 
    HashMap<String, Measure> map = new HashMap<String, Measure>(); 
    measure.setMeasures(map); 
    assertEquals(measure.getMeasures(), map); 
    measure.setMeasures(null); 
    assertEquals(measure.getMeasures(), null); 
} 

@Test 
public void testAllMeasuresData() throws IOException { 
    ClassLoader loader = PowerMockito.mock(ClassLoader.class); 
    Thread threadMock = PowerMockito.mock(Thread.class); 
    Vector<URL> vec = new Vector<URL>(); 
    Mockito.when(loader.getResources("measure")).thenReturn(vec.elements()); 
    Mockito.when(threadMock.getContextClassLoader()).thenReturn(loader); 
    PowerMockito.mockStatic(Thread.class); 
    Mockito.when(Thread.currentThread()).thenReturn(threadMock); 
     ... 
    } 
} 

Während dieses Tests laufen Ich habe:

java.lang.LinkageError: loader constraint violation: loader (instance of org/powermock/core/classloader/MockClassLoader) previously initiated loading for a different type with name "javax/management/MBeanServer" 
at java.lang.ClassLoader.defineClass1(Native Method) 
at java.lang.ClassLoader.defineClass(ClassLoader.java:791) 
at java.lang.ClassLoader.defineClass(ClassLoader.java:634) 
at org.powermock.core.classloader.MockClassLoader.loadUnmockedClass(MockClassLoader.java:201) 
at org.powermock.core.classloader.MockClassLoader.loadModifiedClass(MockClassLoader.java:149) 
at org.powermock.core.classloader.DeferSupportingClassLoader.loadClass(DeferSupportingClassLoader.java:67) 
at java.lang.ClassLoader.loadClass(ClassLoader.java:356) 
at org.codecover.instrumentation.java.measurement.ProtocolImpl.initializeMBean(ProtocolImpl.java:247) 
at org.codecover.instrumentation.java.measurement.ProtocolImpl.<init>(ProtocolImpl.java:237) 
at org.codecover.instrumentation.java.measurement.ProtocolImpl.getInstance(ProtocolImpl.java:185) 
at measure.CodeCoverCoverageCounter$6ya5ud0ow79ijrr1dvjrp4nxx60qhxeua02ta2fzpmb1d.<clinit>(MeasureCalculatorsHolder.java:146) 
at measure.MeasureCalculatorsHolder.<clinit>(MeasureCalculatorsHolder.java:17) 
at java.lang.Class.forName0(Native Method) 
at java.lang.Class.forName(Class.java:188) 
at javassist.runtime.Desc.getClassObject(Desc.java:43) 
at javassist.runtime.Desc.getClassType(Desc.java:152) 
at javassist.runtime.Desc.getType(Desc.java:122) 
at javassist.runtime.Desc.getType(Desc.java:78) 
at algorithm.AllMeasuresDataTest.testGetMeasures(AllMeasuresDataTest.java:26) 
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) 
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57) 
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) 
at java.lang.reflect.Method.invoke(Method.java:601) 
at org.junit.internal.runners.TestMethod.invoke(TestMethod.java:66) 
at org.powermock.modules.junit4.internal.impl.PowerMockJUnit44RunnerDelegateImpl$PowerMockJUnit44MethodRunner.runTestMethod(PowerMockJUnit44RunnerDelegateImpl.java:312) 
at org.junit.internal.runners.MethodRoadie$2.run(MethodRoadie.java:86) 
at org.junit.internal.runners.MethodRoadie.runBeforesThenTestThenAfters(MethodRoadie.java:94) 
at org.powermock.modules.junit4.internal.impl.PowerMockJUnit44RunnerDelegateImpl$PowerMockJUnit44MethodRunner.executeTest(PowerMockJUnit44RunnerDelegateImpl.java:296) 
at org.powermock.modules.junit4.internal.impl.PowerMockJUnit49RunnerDelegateImpl$PowerMockJUnit49MethodRunner.executeTestInSuper(PowerMockJUnit49RunnerDelegateImpl.java:116) 
at org.powermock.modules.junit4.internal.impl.PowerMockJUnit49RunnerDelegateImpl$PowerMockJUnit49MethodRunner.executeTest(PowerMockJUnit49RunnerDelegateImpl.java:77) 
at org.powermock.modules.junit4.internal.impl.PowerMockJUnit44RunnerDelegateImpl$PowerMockJUnit44MethodRunner.runBeforesThenTestThenAfters(PowerMockJUnit44RunnerDelegateImpl.java:284) 
at org.junit.internal.runners.MethodRoadie.runTest(MethodRoadie.java:84) 
at org.junit.internal.runners.MethodRoadie.run(MethodRoadie.java:49) 
at org.powermock.modules.junit4.internal.impl.PowerMockJUnit44RunnerDelegateImpl.invokeTestMethod(PowerMockJUnit44RunnerDelegateImpl.java:209) 
at org.powermock.modules.junit4.internal.impl.PowerMockJUnit44RunnerDelegateImpl.runMethods(PowerMockJUnit44RunnerDelegateImpl.java:148) 
at org.powermock.modules.junit4.internal.impl.PowerMockJUnit44RunnerDelegateImpl$1.run(PowerMockJUnit44RunnerDelegateImpl.java:122) 
at org.junit.internal.runners.ClassRoadie.runUnprotected(ClassRoadie.java:34) 
at org.junit.internal.runners.ClassRoadie.runProtected(ClassRoadie.java:44) 
at org.powermock.modules.junit4.internal.impl.PowerMockJUnit44RunnerDelegateImpl.run(PowerMockJUnit44RunnerDelegateImpl.java:120) 
at org.powermock.modules.junit4.common.internal.impl.JUnit4TestSuiteChunkerImpl.run(JUnit4TestSuiteChunkerImpl.java:101) 
at org.powermock.modules.junit4.common.internal.impl.AbstractCommonPowerMockRunner.run(AbstractCommonPowerMockRunner.java:53) 
at org.powermock.modules.junit4.PowerMockRunner.run(PowerMockRunner.java:53) 
at org.eclipse.jdt.internal.junit4.runner.JUnit4TestReference.run(JUnit4TestReference.java:50) 
at org.eclipse.jdt.internal.junit.runner.TestExecution.run(TestExecution.java:38) 
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:467) 
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:683) 
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.run(RemoteTestRunner.java:390) 
at org.codecover.juniteclipse.runner.EclipseTestRunner.main(EclipseTestRunner.java:40) 

Wissen Sie, wie kann ich das verhindern? Ich vielleicht gibt es einen anderen Weg, ein solches Stück Code zu verspotten:

ClassLoader classLoader = Thread.currentThread().getContextClassLoader(); 
... 
Enumeration<URL> resources = classLoader.getResources(path); 
+0

Was versuchen Sie zu verhöhnen? Und warum? – NilsH

+0

Erster Test ist Getters und Setter Test, ich rufe Konstruktor dort (und dort tritt die Ausnahme auf). Der zweite ist der Konstruktortest. Ich möchte die Kontrolle darüber erlangen, welche Ressourcenaufzählung im dritten Code-Snippet enthalten ist. –

+1

Zunächst sieht es für mich aus, dass Ihre Tests sehr eng an Ihre Implementierung gekoppelt sind. Aus Erfahrung wird dies zu fragilen Tests führen. Vorzugsweise möchten Sie beim Schreiben Ihrer Tests "Black Box" denken. "Was soll dieses Stück Code tun?", Anstatt "Wie macht dieses Stück Code es?". Zweitens denke ich, dass es besser wäre, wenn Sie nur eine Reihe von Ressourcen erstellen und die Java-Laufzeitumgebung mit dem Classloading selbst arbeiten lassen würde. – NilsH

Antwort

236

Versuchen Sie, diese Anmerkung zu Ihrem Test-Klasse hinzufügen:

@PowerMockIgnore("javax.management.*")

Arbeitete für mich.

+2

Woot woot! - Das ist alles, was ich sagen muss ;-) –

+2

Präzision * "zu Ihrer Testklasse". Einfache und nützliche Antwort! – pdem

+1

vielen Dank –

3

Um Mock Systemklassen, bereiten die Klasse, die das Ziel des Tests ist es, nicht Thread.class. Es gibt keine Möglichkeit, dass PowerMock das Instrument Thread.class instrumentieren kann, da es während des JVM-Starts benötigt wird - lange bevor PowerMock es in Betrieb nehmen kann.

Die Art der Instrumentierung funktioniert, sobald eine Klasse geladen ist, kann sie nicht mehr intmetriert werden.

Siehe the PowerMock wiki.

20

Classloader Konflikt, verwenden Sie diese: @PowerMockIgnore("javax.management.*")

Lassen Mock Classloader nicht javax.*. lade Es funktioniert.

+0

Nach der Verwendung von '@PowerMockIgnore (" javax.management. * ")' Funktioniert die Testklasse gut alleine. Aber als 'Junit-Test' auf diesem ** Paket ausgeführt ** hat 'Fehler beim Laden von ApplicationContext' Fehler. 'org.apache.catalina.LifecycleException: Ein untergeordneter Container ist beim Start fehlgeschlagen' und so weiter. – niaomingjian

6

Das mag ein bisschen ein altes Thema sein, aber ich bin auch auf dieses Problem gestoßen. Es stellte sich heraus, dass einige der Java-Versionen nicht mit powermockito umgehen können, wenn powermock herausfindet, dass es im selben Paket zwei Klassen mit demselben Namen gibt (über verschiedene Abhängigkeiten hinweg).

Mit jeder höheren Version als Java 7_25 gibt es diesen Fehler.

+2

"Bei jeder höheren Version als Java 7_25 gibt es diesen Fehler.", Dies ist informativ. –

+0

Was es bedeutet: "Kann powermockito nicht umgehen"? Gibt es eine Möglichkeit, damit umzugehen, abgesehen von der Annotation? – Line

+0

Es ist eine lange Zeit her, aber ich denke, wir haben es aussortiert, indem wir sichergestellt haben, dass es nicht 2 Klassen mit dem gleichen Namen in der gleichen Art von Paket gibt. Natürlich, wenn Sie 2 Bibliotheken haben, auf die Sie angewiesen sind, und sie dort wohnen ... wird es schwierig. Ich weiß nicht, ob dieses Problem in der Zwischenzeit behoben wurde. –

15

Crandrads Antwort half mir, eine ähnliche Lösung zu finden. Am Ende musste ich alle SSL-bezogenen Klassen ausschließen:

@PowerMockIgnore({"javax.management.*", "org.apache.http.conn.ssl.*", "com.amazonaws.http.conn.ssl.*", "javax.net.ssl.*"}) 
+4

Noch benötigt, um ein paar Pfade hinzuzufügen, aber Sie rettete mein Leben Mann! '@PowerMockIgnore ({" javax.management. * "," org.apache.http.conn.ssl. * "," Com.amazonaws. * "," Javax.net.ssl. * "," Com.sun. " * "})' –

+0

Gut zu wissen über com.sun auch. –

+1

Ich brauchte Folgendes: @PowerMockIgnore ({"javax.management. *", "Javax.crypto. *"}) –

Verwandte Themen