Mockito + PowerMock LinkageError під час глузування з системним класом


166

У мене такий фрагмент коду:

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

Під час виконання цих тестів я отримав:

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)

Чи знаєте ви, як я можу запобігти цьому? Я, можливо, є інший спосіб знущатися над таким фрагментом коду:

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

Що це ти намагаєшся знущатися? І чому?
NilsH

Перший тест - це тест на геттери та сетери, я викликаю конструктор там (і там відбувається виняток). Другий - це тест конструктора. Я хочу отримати контроль над тим, що перерахування ресурсів містить у третьому фрагменті коду.
Войцех Резелевський

1
Перш за все, мені здається, що ваші тести дуже щільно поєднані з вашою реалізацією. З досвіду, це призведе до крихких випробувань. Переважно, ви хочете думати про «чорну скриньку», коли пишете свої тести. "Що має робити цей фрагмент коду", а не "Як це робить фрагмент коду". По-друге, я думаю, вам буде краще просто створити набір ресурсів і дозволити Java виконувати час з самим завантаженням класів.
NilsH

Можна створити різні набори ресурсів, як там, де перевіряються справи?
Войцех Резелевський

Звичайно. Найпростішим для вас, мабуть, є параметризація назви ресурсів. Потім ви можете передавати різні назви ресурсів у ваші тести.
NilsH

Відповіді:


408

Спробуйте додати цю примітку до свого тестового класу:

@PowerMockIgnore("javax.management.*")

Працювали для мене.


2
точність * "до вашого тестового класу". Проста і корисна відповідь!
pdem

3
Чи можна це зробити також за допомогою коду чи конфігурації? Я не міг знайти жодного способу це зробити. У нас сотні тестів ... я не можу їх усіх коригувати.
Фредерік Лейтенбергер

1
@FredericLeitenberger дивіться мою відповідь нижче
user3474985

2
Чи можете ви, будь ласка, пояснити інтуїцію та значення цього виправлення? Які вказівки ми даємо PowerMockito за допомогою цієї лінії?
Swapnil B.

33

Подібно до прийнятої тут відповіді, мені довелося виключити всі пов’язані з SSL класи:

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

Додавши це до вершини мого класу, вирішено помилку.


5
Ще потрібно додати ще кілька шляхів, але ти врятував моє життя людині! @PowerMockIgnore({"javax.management.*", "org.apache.http.conn.ssl.*", "com.amazonaws.*", "javax.net.ssl.*","com.sun.*"})
Франсіско Лопес-Санчо

Добре знати і про com.sun.
Джейсон Д

1
Мені потрібно було наступне: @PowerMockIgnore ({"javax.management. *", "Javax.crypto. *"})
Крістоф Нірінк

2
Це врятувало мене: @PowerMockIgnore ({"javax.management. *", "Org.apache.http. *", "Com.amazonaws.http.conn.ssl. *", "Javax.net.ssl. *" , "com.sun. *", "javax.xml. *", "javax.crypto. *"})
Фаяз Ахмед

26

Конфлікт завантажувача класів , використовуйте це:@PowerMockIgnore("javax.management.*")

Нехай макет-завантажувач не завантажує. javax.*. Це працює.


Після використання @PowerMockIgnore("javax.management.*")тестовий клас працює добре окремо. Але запуск Junit testу тому пакеті отримав Failed to load ApplicationContextпомилку. org.apache.catalina.LifecycleException: A child container failed during startі так далі.
niaomingjian

8

Це може бути трохи старою темою, але я також зіткнувся з цією проблемою. Виявляється, деякі версії java не можуть працювати з powermockito, коли powermock виявить, що в одному пакеті (за різних залежностей) є два класи з однаковою назвою.

З будь-якою версією, що перевищує Java 7_25, ця помилка дає.


2
"З будь-якою версією, що перевищує Java 7_25, вона дає цю помилку.", Це інформативно.
Kajal Sinha

Що це означає: "не можна впоратися з powermockito"? Чи є якийсь спосіб впоратися з цим, окрім ігнорування анотацією?
Рядок

Це було дуже давно, але я думаю, що ми розібралися, переконавшись, що в одному пакеті немає двох класів з однаковою назвою. Звичайно, якщо у вас є 2 бібліотеки, від яких ви залежите, і вони проживають там ... це буде важко. Я не знаю, чи це питання тим часом було виправлено.
Ренс Гроенвельд

3

Щоб знущатися із системних класів, підготуйте клас, який є ціллю тесту, а не Thread.class. PowerMock не зможе інструментувати, Thread.classтому що це потрібно під час запуску JVM - задовго до того, як PowerMock зможе прилад.

Те, як працює інструментарій, щойно клас завантажується, він більше не може бути інструментований.

Дивіться вікі PowerMock .


3

У PowerMock 1.7.0 до класного шляху вашого проекту може бути додана визначена користувачем глобальна конфігурація. PowerMockConfig

org/powermock/extensions/configuration.properties

Просто додайте рядок у файл властивостей, наприклад:

powermock.global-ignore=javax.management.*

Це дозволить усунути помилку для всіх тестових класів у вашому проекті.

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.