使用 Powermock 模拟类的构造函数时出现 ExceptionInInitializerError。如何修复它?

发布于 2024-12-07 06:33:46 字数 4734 浏览 1 评论 0原文

这是我的案例。我有一个 AbstractController 类。它有一个子类Controller。在 AbstractController 的方法之一中,实例化了一个新的 ApplicationLock。我想在为控制器编写 ut 时模拟 ApplicationLock 。我写了一个如下的测试用例。

@test
public void testMethod(){
    ApplicationLock mockLock=PowerMockito.mock(ApplicationLock.class);
    PowerMockito.when(mockLock.tryObtain()).thenReturn(true);
    PowerMockito.whenNew(ApplicationLock.class).withArguments(argThat(new IsFile()),anyString()).thenReturn(mockLock);
}

我已经向测试类添加了必要的注释。

@RunWith(PowerMockRunner.class)

@PrepareForTest({AbstractController.class})

但运行此测试用例时出现以下错误。这是 AbstractController 中的静态初始值设定项。

原因:java.lang.NullPointerException 在 com.acompany.controller.common.AbstractController.(AbstractController.java:65)

private static final String DEFAULT_FOLDER = AbstractController.class.getProtectionDomain().getCodeSource()
            .getLocation().getPath();

完整堆栈跟踪如下。

java.lang.ExceptionInInitializerError 位于 java.lang.Class.forName0(本机方法) at java.lang.Class.forName(Class.java:169) 在 javassist.runtime.Desc.getClassObject(Desc.java:44) 位于 javassist.runtime.Desc.getClassType(Desc.java:153) 位于 javassist.runtime.Desc.getType(Desc.java:123) 位于 javassist.runtime.Desc.getType(Desc.java:79) 位于 com.acompany.controller.portfolio.ControllerTest.testIncrementalFail(ControllerTest.java:195) 在 sun.reflect.NativeMethodAccessorImpl.invoke0(本机方法) 处 sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39) 在 sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25) 在 java.lang.reflect.Method.invoke(Method.java:597) 处 org.junit.internal.runners.TestMethod.invoke(TestMethod.java:66) 在 org.powermock.modules.junit4.internal.impl.PowerMockJUnit44RunnerDelegateImpl$PowerMockJUnit44MethodRunner.runTestMethod(PowerMockJUnit44RunnerDelegateImpl.java:307) 在 org.junit.internal.runners.MethodRoadie$2.run(MethodRoadie.java:86) 在 org.junit.internal.runners.MethodRoadie.runBeforesThenTestThenAfters(MethodRoadie.java:94) 在 org.powermock.modules.junit4.internal.impl.PowerMockJUnit44RunnerDelegateImpl$PowerMockJUnit44MethodRunner.executeTest(PowerMockJUnit44RunnerDelegateImpl.java:294) 在 org.powermock.modules.junit4.internal.impl.PowerMockJUnit47RunnerDelegateImpl$PowerMockJUnit47MethodRunner.executeTestInSuper(PowerMockJUnit47RunnerDelegateImpl.java:112) 在 org.powermock.modules.junit4.internal.impl.PowerMockJUnit47RunnerDelegateImpl$PowerMockJUnit47MethodRunner.executeTest(PowerMockJUnit47RunnerDelegateImpl.java:73) 在 org.powermock.modules.junit4.internal.impl.PowerMockJUnit44RunnerDelegateImpl$PowerMockJUnit44MethodRunner.runBeforesThenTestThenAfters(PowerMockJUnit44RunnerDelegateImpl.java:282) 在 org.junit.internal.runners.MethodRoadie.runTest(MethodRoadie.java:84) 在 org.junit.internal.runners.MethodRoadie.run(MethodRoadie.java:49) 在 org.powermock.modules.junit4.internal.impl.PowerMockJUnit44RunnerDelegateImpl.invokeTestMethod(PowerMockJUnit44RunnerDelegateImpl.java:207) 在 org.powermock.modules.junit4.internal.impl.PowerMockJUnit44RunnerDelegateImpl.runMethods(PowerMockJUnit44RunnerDelegateImpl.java:146) 在 org.powermock.modules.junit4.internal.impl.PowerMockJUnit44RunnerDelegateImpl$1.run(PowerMockJUnit44RunnerDelegateImpl.java:120) 在 org.junit.internal.runners.ClassRoadie.runUnprotected(ClassRoadie.java:34) 在 org.junit.internal.runners.ClassRoadie.runProtected(ClassRoadie.java:44) 在 org.powermock.modules.junit4.internal.impl.PowerMockJUnit44RunnerDelegateImpl.run(PowerMockJUnit44RunnerDelegateImpl.java:118) 在 org.powermock.modules.junit4.common.internal.impl.JUnit4TestSuiteChunkerImpl.run(JUnit4TestSuiteChunkerImpl.java:102) 在 org.powermock.modules.junit4.common.internal.impl.AbstractCommonPowerMockRunner.run(AbstractCommonPowerMockRunner.java:53) 在 org.eclipse.jdt.internal.junit4.runner.JUnit4TestReference.run(JUnit4TestReference.java:49) 在 org.eclipse.jdt.internal.junit.runner.TestExecution.run(TestExecution.java:38) 在 org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:467) 在 org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:683) 在 org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.run(RemoteTestRunner.java:390) 在 org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.main(RemoteTestRunner.java:197) 导致:java.lang.NullPointerException at com.acompany.controller.common.AbstractController.(AbstractController.java:65) ... 35 更多

Here is my case. I have a AbstractController class. It has a sub class Controller. In one of AbstractController's methods a new ApplicationLock is instantiated. I'd like to mock ApplicationLock when writing ut for Controller. I wrote a test case like below.

@test
public void testMethod(){
    ApplicationLock mockLock=PowerMockito.mock(ApplicationLock.class);
    PowerMockito.when(mockLock.tryObtain()).thenReturn(true);
    PowerMockito.whenNew(ApplicationLock.class).withArguments(argThat(new IsFile()),anyString()).thenReturn(mockLock);
}

I've added necessary annotations to the test class.

@RunWith(PowerMockRunner.class)

@PrepareForTest({AbstractController.class})

But I got the following error when running this test case. That is a static initializer in AbstractController.

Caused by: java.lang.NullPointerException
at com.acompany.controller.common.AbstractController.(AbstractController.java:65)

private static final String DEFAULT_FOLDER = AbstractController.class.getProtectionDomain().getCodeSource()
            .getLocation().getPath();

Full stack trace is as below.

java.lang.ExceptionInInitializerError at
java.lang.Class.forName0(Native Method) at
java.lang.Class.forName(Class.java:169) at
javassist.runtime.Desc.getClassObject(Desc.java:44) at
javassist.runtime.Desc.getClassType(Desc.java:153) at
javassist.runtime.Desc.getType(Desc.java:123) at
javassist.runtime.Desc.getType(Desc.java:79) at
com.acompany.controller.portfolio.ControllerTest.testIncrementalFail(ControllerTest.java:195)
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:307)
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:294)
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:282)
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:207)
at
org.powermock.modules.junit4.internal.impl.PowerMockJUnit44RunnerDelegateImpl.runMethods(PowerMockJUnit44RunnerDelegateImpl.java:146)
at
org.powermock.modules.junit4.internal.impl.PowerMockJUnit44RunnerDelegateImpl$1.run(PowerMockJUnit44RunnerDelegateImpl.java:120)
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:118)
at
org.powermock.modules.junit4.common.internal.impl.JUnit4TestSuiteChunkerImpl.run(JUnit4TestSuiteChunkerImpl.java:102)
at
org.powermock.modules.junit4.common.internal.impl.AbstractCommonPowerMockRunner.run(AbstractCommonPowerMockRunner.java:53)
at
org.eclipse.jdt.internal.junit4.runner.JUnit4TestReference.run(JUnit4TestReference.java:49)
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.eclipse.jdt.internal.junit.runner.RemoteTestRunner.main(RemoteTestRunner.java:197)
Caused by: java.lang.NullPointerException at
com.acompany.controller.common.AbstractController.(AbstractController.java:65)
... 35 more

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

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

发布评论

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

评论(1

挽袖吟 2024-12-14 06:33:46

您可以使用 then:

 @SuppressStaticInitializationFor({AbstractController.class})

然后,在您的测试用例中,手动设置需要初始化的所有静态字段,包​​括 DEFAULT_FOLDER:

Whitebox.setInternalState(Controller.class, "DEFAULT_FOLDER", "abcd");
Whitebox.setInternalState(Controller.class, "OTHER_FIELD", new Object());

方法 Class.getProtectionDomain() 依赖于太多使用了类加载器,因此您可能无法让它在 JUnit/PowerMock 中工作,因为它们使用自己的类加载器。

You could use then:

 @SuppressStaticInitializationFor({AbstractController.class})

And then, in your test case, set manually all static fields that need to be initialized, including the DEFAULT_FOLDER:

Whitebox.setInternalState(Controller.class, "DEFAULT_FOLDER", "abcd");
Whitebox.setInternalState(Controller.class, "OTHER_FIELD", new Object());

The method Class<?>.getProtectionDomain() depends too much on class loader used, so you probably won't get it to work in JUnit/PowerMock, which use their own.

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