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

Попробуйте добавить эту аннотацию к вашему классу Test:

@PowerMockIgnore("javax.management.*")

Работал на меня.


2
точность * "к вашему тестовому классу". Простой и полезный ответ!
Pdem

3
Это можно сделать с помощью кода или конфигурации? Я не мог найти способ сделать это. У нас есть сотни тестов ... я не могу настроить их все.
Фредерик Лейтенбергер

1
@FredericLeitenberger смотрите мой ответ ниже
user3474985

2
Не могли бы вы также объяснить интуицию и значение этого исправления? Какую инструкцию мы даем PowerMockito, используя эту строку?
Свопнил Б.

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.*")

Пусть mock classloader не загружается 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 обнаруживает, что в одном и том же пакете 2 класса с одинаковым именем (в разных зависимостях).

С любой версией выше Java 7_25 выдает эту ошибку.


2
«С любой версией выше Java 7_25 выдает эту ошибку.» Это информативно.
Каджал Синха

Что это значит: «не справиться с 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.