Mockito + PowerMock LinkageError trong khi chế độ lớp hệ thống


165

Tôi đã có một đoạn mã như vậy:

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

Trong khi chạy thử nghiệm này, tôi nhận được:

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)

Bạn có biết làm thế nào tôi có thể ngăn chặn điều này? Tôi có thể có một cách khác để chế nhạo một đoạn mã như vậy:

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

Bạn đang cố gắng để chế giễu điều gì? Và tại sao?
NilsH

Thử nghiệm đầu tiên là thử nghiệm getters và setters, tôi đang gọi hàm tạo ở đó (và có ngoại lệ xảy ra). Cái thứ hai là kiểm tra constructor. Tôi muốn có quyền kiểm soát liệt kê tài nguyên chứa trong đoạn mã thứ ba.
Wojciech Reszelewski

1
Trước hết, đối với tôi, các bài kiểm tra của bạn được kết hợp rất chặt chẽ với việc thực hiện của bạn. Theo kinh nghiệm, điều này sẽ dẫn đến các bài kiểm tra mong manh. Tốt hơn là, bạn muốn nghĩ "hộp đen" khi viết bài kiểm tra của mình. "Đoạn mã này phải làm gì", chứ không phải là "Đoạn mã này thực hiện như thế nào". Thứ hai, tôi nghĩ rằng bạn sẽ tốt hơn nếu chỉ tạo một tập hợp các tài nguyên và để cho thời gian chạy Java xử lý chính việc nạp lớp.
NilsH

Có thể tạo ra các bộ tài nguyên khác nhau, khi chúng là trường hợp thử nghiệm?
Wojciech Reszelewski

Chắc chắn rồi. Đơn giản nhất đối với bạn có lẽ là tham số tên của các tài nguyên. Sau đó, bạn có thể chuyển các tên tài nguyên khác nhau vào các bài kiểm tra của mình.
NilsH

Câu trả lời:


407

Hãy thử thêm chú thích này vào lớp Test của bạn:

@PowerMockIgnore("javax.management.*")

Đã làm cho tôi.


2
độ chính xác * "cho lớp kiểm tra của bạn". Câu trả lời đơn giản và hữu ích!
pdem

3
Điều này có thể được thực hiện bằng mã hoặc cấu hình là tốt? Tôi không thể tìm ra cách nào để làm điều này. Chúng tôi có hàng trăm bài kiểm tra ... tôi không thể điều chỉnh tất cả.
Frederic Leitenberger

1
@FredericLeitenberger xem câu trả lời của tôi dưới đây
user3474985

2
Bạn có thể vui lòng giải thích sự can thiệp và ý nghĩa của sửa chữa này? Chúng tôi đang hướng dẫn gì cho PowerMockito khi sử dụng dòng đó?
Swapnil B.

33

Tương tự như phản hồi được chấp nhận ở đây, cuối cùng tôi đã phải loại trừ tất cả các lớp liên quan đến SSL:

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

Thêm điều đó vào đầu lớp tôi đã giải quyết lỗi.


5
Vẫn cần thêm một số con đường nữa nhưng bạn đã cứu người đàn ông của tôi! @PowerMockIgnore({"javax.management.*", "org.apache.http.conn.ssl.*", "com.amazonaws.*", "javax.net.ssl.*","com.sun.*"})
Francisco López-Sancho

Cũng tốt để biết về com.sun.
Jason D

1
Tôi cần những thứ sau: @PowerMockIgnore ({"javax.man Quản lý. *", "Javax.crypto. *"})
Kristof Neirynck

2
Cái này đã cứu tôi: @PowerMockIgnore ({"javax.man Quản lý. *", "Org , "com.sun. *", "javax.xml. *", "javax.crypto. *"})
Fayaz Ahmed

26

Classloader xung đột, sử dụng này:@PowerMockIgnore("javax.management.*")

Để mock classloader không tải javax.*. Nó hoạt động.


Sau khi sử dụng @PowerMockIgnore("javax.management.*"), lớp kiểm tra hoạt động tốt đơn lẻ. Nhưng chạy như Junit testtrên gói đó có Failed to load ApplicationContextlỗi. org.apache.catalina.LifecycleException: A child container failed during startvà như thế.
niaomingjian

8

Đây có thể là một chút của một chủ đề cũ, nhưng tôi cũng đã gặp phải vấn đề này. Hóa ra một số phiên bản java không thể xử lý powermockito khi powermock phát hiện ra có 2 lớp có cùng tên trong cùng một gói (qua các phụ thuộc khác nhau).

Với bất kỳ phiên bản nào cao hơn Java 7_25, nó sẽ báo lỗi này.


2
"Với bất kỳ phiên bản nào cao hơn Java 7_25, nó sẽ báo lỗi này.", Đây là thông tin.
Kajal Sinha

Điều đó có nghĩa là gì: "không thể xử lý powermockito"? Có cách nào để đối phó với nó ngoài việc bỏ qua bằng chú thích?
Dòng

Cách đây đã lâu, nhưng tôi nghĩ rằng chúng tôi đã sắp xếp nó bằng cách đảm bảo không có 2 lớp có cùng tên trong cùng một loại gói. Tất nhiên, nếu bạn có 2 thư viện mà bạn phụ thuộc và chúng nằm trong đó ... điều đó sẽ khó khăn. Tôi không biết vấn đề này đã được khắc phục trong thời gian này chưa.
Rens Groenveld

3

Để chế nhạo các lớp hệ thống, hãy chuẩn bị lớp là mục tiêu của bài kiểm tra, không Thread.class. Không có cách nào PowerMock có thể sử dụng thiết bị Thread.classvì nó được yêu cầu trong quá trình khởi động JVM - trước cả khi PowerMock có thể sử dụng.

Cách thức hoạt động của thiết bị, một khi một lớp được tải, nó không còn có thể được hiểu.

Xem wiki PowerMock .


3

Trong PowerMock 1.7.0, cấu hình toàn cầu do người dùng định nghĩa có thể được thêm vào đường dẫn lớp dự án của bạn. PowerMockConfig

org/powermock/extensions/configuration.properties

Chỉ cần thêm một dòng trong tệp thuộc tính như:

powermock.global-ignore=javax.management.*

Điều này sẽ giải quyết lỗi cho tất cả các lớp kiểm tra trong dự án của bạn.

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.