PowerMock:模拟 java.util.ServiceLoader 时出现 java.lang.IllegalAccessError:java.lang.Class

发布于 2024-10-29 05:14:55 字数 5736 浏览 1 评论 0原文

我试图在使用 PowerMock 的测试中模拟 java ServicesLoader (这是 final),但它似乎失败了......

重现错误的最简单的测试用例是this:

import java.util.ServiceLoader;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.powermock.api.easymock.PowerMock;
import org.powermock.core.classloader.annotations.PrepareForTest;
import org.powermock.modules.junit4.PowerMockRunner;

@RunWith(PowerMockRunner.class)
@PrepareForTest(ServiceLoader.class)
public class ServiceLoaderTest {
    @Test
    public void testServiceLoaderMock() {
        ServiceLoader mock = PowerMock.createMock(ServiceLoader.class);
    }
}

我得到的例外是:

-------------------------------------------------------------------------------
Test set: ServiceLoaderTest
-------------------------------------------------------------------------------
Tests run: 1, Failures: 0, Errors: 1, Skipped: 0, Time elapsed: 0.407 sec <<< FAILURE!
testServiceLoaderMock(ServiceLoaderTest)  Time elapsed: 0.359 sec  <<< ERROR!
java.lang.IllegalAccessError: java.lang.Class
        at sun.reflect.GeneratedSerializationConstructorAccessor8.newInstance(Unknown Source)
        at java.lang.reflect.Constructor.newInstance(Constructor.java:513)
        at org.objenesis.instantiator.sun.SunReflectionFactoryInstantiator.newInstance(SunReflectionFactoryInstantiator.java:56)
        at org.powermock.reflect.internal.WhiteboxImpl.newInstance(WhiteboxImpl.java:257)
        at org.powermock.reflect.Whitebox.newInstance(Whitebox.java:139)
        at org.powermock.core.DefaultFieldValueGenerator.instantiateFieldType(DefaultFieldValueGenerator.java:74)
        at org.powermock.core.DefaultFieldValueGenerator.fillWithDefaultValues(DefaultFieldValueGenerator.java:51)
        at org.powermock.api.easymock.PowerMock.doMock(PowerMock.java:2146)
        at org.powermock.api.easymock.PowerMock.createMock(PowerMock.java:98)
        at ServiceLoaderTest.testServiceLoaderMock(ServiceLoaderTest.java:12)
        at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
        at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
        at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
        at java.lang.reflect.Method.invoke(Method.java:597)
        at org.junit.internal.runners.TestMethod.invoke(TestMethod.java:66)
        at org.powermock.modules.junit4.internal.impl.PowerMockJUnit44RunnerDelegateImpl$PowerMockJUnit44MethodRunner.runTestMethod(PowerMockJUnit44RunnerDelegateImpl.java:322)
        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:309)
        at org.powermock.modules.junit4.internal.impl.PowerMockJUnit47RunnerDelegateImpl$PowerMockJUnit47MethodRunner.executeTestInSuper(PowerMockJUnit47RunnerDelegateImpl.java:112)
        at org.powermock.modules.junit4.internal.impl.PowerMockJUnit47RunnerDelegateImpl$PowerMockJUnit47MethodRunner.executeTest(PowerMockJUnit47RunnerDelegateImpl.java:73)
        at org.powermock.modules.junit4.internal.impl.PowerMockJUnit44RunnerDelegateImpl$PowerMockJUnit44MethodRunner.runBeforesThenTestThenAfters(PowerMockJUnit44RunnerDelegateImpl.java:297)
        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:222)
        at org.powermock.modules.junit4.internal.impl.PowerMockJUnit44RunnerDelegateImpl.runMethods(PowerMockJUnit44RunnerDelegateImpl.java:161)
        at org.powermock.modules.junit4.internal.impl.PowerMockJUnit44RunnerDelegateImpl$1.run(PowerMockJUnit44RunnerDelegateImpl.java:135)
        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:133)
        at org.powermock.modules.junit4.common.internal.impl.JUnit4TestSuiteChunkerImpl.run(JUnit4TestSuiteChunkerImpl.java:112)
        at org.powermock.modules.junit4.common.internal.impl.AbstractCommonPowerMockRunner.run(AbstractCommonPowerMockRunner.java:57)
        at org.apache.maven.surefire.junit4.JUnit4TestSet.execute(JUnit4TestSet.java:62)
        at org.apache.maven.surefire.suite.AbstractDirectoryTestSuite.executeTestSet(AbstractDirectoryTestSuite.java:140)
        at org.apache.maven.surefire.suite.AbstractDirectoryTestSuite.execute(AbstractDirectoryTestSuite.java:127)
        at org.apache.maven.surefire.Surefire.run(Surefire.java:177)
        at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
        at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
        at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
        at java.lang.reflect.Method.invoke(Method.java:597)
        at org.apache.maven.surefire.booter.SurefireBooter.runSuitesInProcess(SurefireBooter.java:345)
        at org.apache.maven.surefire.booter.SurefireBooter.main(SurefireBooter.java:1009)

我想这与对服务的 Class字段进行一些初始化有关,但我不确定。

一旦我解决了这个问题,我还想模拟静态方法 ServiceLoader.load(Class) 以返回之前创建的模拟,因此可能会出现更多问题...

关于如何进行的任何想法解决它吗?

I am trying to mock the java ServicesLoader (which is final) in my tests with PowerMock, and it seems to fail...

The simplest test case that reproduces the error is this:

import java.util.ServiceLoader;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.powermock.api.easymock.PowerMock;
import org.powermock.core.classloader.annotations.PrepareForTest;
import org.powermock.modules.junit4.PowerMockRunner;

@RunWith(PowerMockRunner.class)
@PrepareForTest(ServiceLoader.class)
public class ServiceLoaderTest {
    @Test
    public void testServiceLoaderMock() {
        ServiceLoader mock = PowerMock.createMock(ServiceLoader.class);
    }
}

And the exception I get is:

-------------------------------------------------------------------------------
Test set: ServiceLoaderTest
-------------------------------------------------------------------------------
Tests run: 1, Failures: 0, Errors: 1, Skipped: 0, Time elapsed: 0.407 sec <<< FAILURE!
testServiceLoaderMock(ServiceLoaderTest)  Time elapsed: 0.359 sec  <<< ERROR!
java.lang.IllegalAccessError: java.lang.Class
        at sun.reflect.GeneratedSerializationConstructorAccessor8.newInstance(Unknown Source)
        at java.lang.reflect.Constructor.newInstance(Constructor.java:513)
        at org.objenesis.instantiator.sun.SunReflectionFactoryInstantiator.newInstance(SunReflectionFactoryInstantiator.java:56)
        at org.powermock.reflect.internal.WhiteboxImpl.newInstance(WhiteboxImpl.java:257)
        at org.powermock.reflect.Whitebox.newInstance(Whitebox.java:139)
        at org.powermock.core.DefaultFieldValueGenerator.instantiateFieldType(DefaultFieldValueGenerator.java:74)
        at org.powermock.core.DefaultFieldValueGenerator.fillWithDefaultValues(DefaultFieldValueGenerator.java:51)
        at org.powermock.api.easymock.PowerMock.doMock(PowerMock.java:2146)
        at org.powermock.api.easymock.PowerMock.createMock(PowerMock.java:98)
        at ServiceLoaderTest.testServiceLoaderMock(ServiceLoaderTest.java:12)
        at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
        at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
        at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
        at java.lang.reflect.Method.invoke(Method.java:597)
        at org.junit.internal.runners.TestMethod.invoke(TestMethod.java:66)
        at org.powermock.modules.junit4.internal.impl.PowerMockJUnit44RunnerDelegateImpl$PowerMockJUnit44MethodRunner.runTestMethod(PowerMockJUnit44RunnerDelegateImpl.java:322)
        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:309)
        at org.powermock.modules.junit4.internal.impl.PowerMockJUnit47RunnerDelegateImpl$PowerMockJUnit47MethodRunner.executeTestInSuper(PowerMockJUnit47RunnerDelegateImpl.java:112)
        at org.powermock.modules.junit4.internal.impl.PowerMockJUnit47RunnerDelegateImpl$PowerMockJUnit47MethodRunner.executeTest(PowerMockJUnit47RunnerDelegateImpl.java:73)
        at org.powermock.modules.junit4.internal.impl.PowerMockJUnit44RunnerDelegateImpl$PowerMockJUnit44MethodRunner.runBeforesThenTestThenAfters(PowerMockJUnit44RunnerDelegateImpl.java:297)
        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:222)
        at org.powermock.modules.junit4.internal.impl.PowerMockJUnit44RunnerDelegateImpl.runMethods(PowerMockJUnit44RunnerDelegateImpl.java:161)
        at org.powermock.modules.junit4.internal.impl.PowerMockJUnit44RunnerDelegateImpl$1.run(PowerMockJUnit44RunnerDelegateImpl.java:135)
        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:133)
        at org.powermock.modules.junit4.common.internal.impl.JUnit4TestSuiteChunkerImpl.run(JUnit4TestSuiteChunkerImpl.java:112)
        at org.powermock.modules.junit4.common.internal.impl.AbstractCommonPowerMockRunner.run(AbstractCommonPowerMockRunner.java:57)
        at org.apache.maven.surefire.junit4.JUnit4TestSet.execute(JUnit4TestSet.java:62)
        at org.apache.maven.surefire.suite.AbstractDirectoryTestSuite.executeTestSet(AbstractDirectoryTestSuite.java:140)
        at org.apache.maven.surefire.suite.AbstractDirectoryTestSuite.execute(AbstractDirectoryTestSuite.java:127)
        at org.apache.maven.surefire.Surefire.run(Surefire.java:177)
        at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
        at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
        at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
        at java.lang.reflect.Method.invoke(Method.java:597)
        at org.apache.maven.surefire.booter.SurefireBooter.runSuitesInProcess(SurefireBooter.java:345)
        at org.apache.maven.surefire.booter.SurefireBooter.main(SurefireBooter.java:1009)

I guess it has something to do with doing some initialisation of the Class<T> field of the service, but I don't know for sure.

Once I have fixed this, I would like also to mock the static method ServiceLoader.load(Class) to return the previously created mock, so there might be more problems to come...

Any idea on how to solve it?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

单身狗的梦 2024-11-05 05:14:55

看看这篇文章: 模拟 java 系统类中的静态方法,或者更具体地说,名为 的部分“但是等等,这对最终系统类有效吗?”

引自文章:

但是最终的系统类呢? PowerMock 无法删除系统类的 Final 修饰符,那么该怎么办呢? PowerMock 在这些情况下所做的是在运行时创建一个全新的类,其结构与原始最终系统类完全相同。即所有方法名称及其相应的签名都被复制到这个新的副本类中。为了允许部分模拟副本类的所有静态方法,委托给最终系统类中的原始方法。它也是被底层模拟框架模拟的副本类,而不是原始系统类。然后,MockGateway 发现绑定到该特定系统类的所有方法都应该路由到副本模拟。因此,模拟最终系统类(例如 java.lang.System 或 java.lang.String)中的静态方法也有效。顺便说一句,实际上也可以使用这种技术在 Java 中实现鸭子类型。不管怎样,这里有一个例子来演示我们刚才所说的内容:

 public class SystemPropertyMockDemo {

    public String getSystemProperty() throws IOException {
        return System.getProperty("property");
    }
}

@RunWith(PowerMockRunner.class)
@PrepareForTest( { SystemPropertyMockDemo.class, SystemPropertyMockDemoTest.class })
public class SystemPropertyMockDemoTest

    @Test
    public void demoOfFinalSystemClassMocking() throws Exception {
        mockStatic(System.class);

        expect(System.getProperty("property")).andReturn("my property");

        replayAll();

        assertEquals("my property",
                                  new SystemPropertyMockDemo().getSystemProperty());

        verifyAll();
    }
}

Have a look at this article: Mocking static methods in java system classes, or more specifically, the section called "But wait, will this work for final system classes?".

Quoted from the article:

But what about a final system class? There's no way for PowerMock to remove the final modifier of a system class so what to do? What PowerMock does in these cases is to create a completely new class at run-time with the exact same structure as the original final system class. I.e. all method names and their corresponding signature are copied to a this new replica class. To allow for partial mocking all static methods of the replica class delegates to the original method in the final system class. It's also the replica class that is being mocked by the underlying mock framework instead of the original system class. The MockGateway then figures out that all methods bound for this particular system class should be routed to the replica mock instead. Thus mocking of static methods in final system classes such as java.lang.System or java.lang.String works as well. As a side note it would actually be possible to use this technique to implement duck-typing in Java as well. Anyway, here's an example to demonstrate what we've just said:

 public class SystemPropertyMockDemo {

    public String getSystemProperty() throws IOException {
        return System.getProperty("property");
    }
}

@RunWith(PowerMockRunner.class)
@PrepareForTest( { SystemPropertyMockDemo.class, SystemPropertyMockDemoTest.class })
public class SystemPropertyMockDemoTest

    @Test
    public void demoOfFinalSystemClassMocking() throws Exception {
        mockStatic(System.class);

        expect(System.getProperty("property")).andReturn("my property");

        replayAll();

        assertEquals("my property",
                                  new SystemPropertyMockDemo().getSystemProperty());

        verifyAll();
    }
}
素食主义者 2024-11-05 05:14:55

这似乎是一个错误。从邮件列表中得到答案:

http://groups.google.com/group /powermock/browse_thread/thread/4afafbfdf1b3ce58

It seemed to be a bug. Got the answer from the mailing list:

http://groups.google.com/group/powermock/browse_thread/thread/4afafbfdf1b3ce58

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文