Mockito + PowerMock LinkageError mentre deride la classe di sistema


166

Ho un frammento di codice simile:

@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);
        ...
    }
}

Durante l'esecuzione di questi test ho ottenuto:

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)

Sai come posso impedirlo? Forse c'è un altro modo per deridere un tale codice:

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

Cosa stai cercando di deridere? E perché?
NilsH,

Il primo test è getter e setter test, sto chiamando il costruttore lì (e lì si verifica l'eccezione). Il secondo è il test del costruttore. Voglio ottenere il controllo di ciò che l'enumerazione delle risorse contiene nel terzo frammento di codice.
Wojciech Reszelewski,

1
Prima di tutto, mi sembra che i tuoi test siano strettamente associati alla tua implementazione. Per esperienza, questo porterà a fragili test. Preferibilmente, vuoi pensare a "scatola nera" quando scrivi i tuoi test. "Cosa dovrebbe fare questo pezzo di codice", piuttosto che "Come lo sta facendo questo pezzo di codice". In secondo luogo, penso che sarebbe meglio creare un set di risorse e lasciare che il runtime Java gestisca il caricamento delle classi stesso.
NilsH,

È possibile creare vari insiemi di risorse, in quanto sono casi di test?
Wojciech Reszelewski,

Sicuro. Il più semplice per te è probabilmente quello di parametrizzare il nome delle risorse. Quindi è possibile passare nomi di risorse diversi nei test.
NilsH,

Risposte:


408

Prova ad aggiungere questa annotazione alla tua classe Test:

@PowerMockIgnore("javax.management.*")

Ha funzionato per me.


2
precisione * "alla tua classe di prova". Risposta semplice e utile!
pdem

3
Questo può essere fatto anche tramite codice o configurazione? Non sono riuscito a trovare alcun modo per farlo. Abbiamo centinaia di test ... non riesco a regolarli tutti.
Frederic Leitenberger,

1
@FredericLeitenberger vedi la mia risposta qui sotto
user3474985

2
Potete per favore spiegare anche l'intuizione e il significato di questa correzione? Quali istruzioni stiamo dando a PowerMockito usando quella linea?
Swapnil B.

33

Simile alla risposta accettata qui, ho finito per dover escludere tutte le classi relative a SSL:

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

L'aggiunta alla cima della mia classe ha risolto l'errore.


5
Avevo ancora bisogno di aggiungere altri percorsi ma mi hai salvato la vita amico! @PowerMockIgnore({"javax.management.*", "org.apache.http.conn.ssl.*", "com.amazonaws.*", "javax.net.ssl.*","com.sun.*"})
Francisco López-Sancho,

Buono a sapersi anche su com.sun.
Jason D,

1
Avevo bisogno di quanto segue: @PowerMockIgnore ({"javax.management. *", "Javax.crypto. *"})
Kristof Neirynck,

2
Questo mi ha salvato: @PowerMockIgnore ({"javax.management. *", "Org.apache.http. *", "Com.amazonaws.http.conn.ssl. *", "Javax.net.ssl. *" , "com.sun. *", "javax.xml. *", "javax.crypto. *"})
Fayaz Ahmed

26

Conflitto di Classloader , utilizzare questo:@PowerMockIgnore("javax.management.*")

Lascia che il finto classloader non carichi javax.*. Funziona.


Dopo l'uso @PowerMockIgnore("javax.management.*"), la classe di test funziona bene singolarmente. Ma l'esecuzione come Junit testsu quel pacchetto ha avuto un Failed to load ApplicationContexterrore. org.apache.catalina.LifecycleException: A child container failed during starte così via.
niaomingjian,

8

Questo potrebbe essere un po 'un vecchio argomento, ma ho anche riscontrato questo problema. Si scopre che alcune delle versioni java non sono in grado di gestire powermockito quando powermock scopre che ci sono 2 classi con lo stesso nome nello stesso pacchetto (su dipendenze diverse).

Con qualsiasi versione successiva a Java 7_25 fornisce questo errore.


2
"Con qualsiasi versione successiva a Java 7_25 fornisce questo errore.", Questo è informativo.
Kajal Sinha,

Cosa significa: "impossibile gestire powermockito"? C'è un modo per affrontarlo oltre a ignorare per annotazione?
Linea

È molto tempo fa, ma penso che l'abbiamo risolto assicurandoci che non ci siano 2 classi con lo stesso nome nello stesso tipo di pacchetto. Certo, se hai 2 librerie dalle quali dipendi, e risiedono lì dentro ... sarà difficile. Non so se questo problema è stato risolto nel frattempo.
Rens Groenveld,

3

Per deridere le classi di sistema, preparare la classe che è la destinazione del test Thread.class. Non è possibile che PowerMock sia in grado di strumentare Thread.classperché è necessario durante l'avvio di JVM, ben prima che PowerMock possa eseguire la strumentazione.

Il modo in cui funziona la strumentazione, una volta caricata una classe, non può più essere strumentata.

Vedi la wiki di PowerMock .


3

In PowerMock 1.7.0 è possibile aggiungere una configurazione globale definita dall'utente al percorso di classe del progetto. PowerMockConfig

org/powermock/extensions/configuration.properties

Aggiungi semplicemente una riga nel file delle proprietà come:

powermock.global-ignore=javax.management.*

Ciò risolverà l'errore per tutte le classi di test nel progetto.

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.