SSLContext 模拟未按预期运行
SSLContext mock not behaving as expected
我有以下简单的 class:
导入 javax.net.ssl.SSLContext;
public class AClass {
public void someMethod() throws Exception {
SSLContext context = SSLContext.getInstance("SSL");
context.init(null, null, null);
}
}
及其 JUnit:
导入 javax.net.ssl.SSLContext;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.Mockito;
import org.powermock.api.mockito.PowerMockito;
import org.powermock.core.classloader.annotations.PrepareForTest;
import org.powermock.modules.junit4.PowerMockRunner;
@RunWith(PowerMockRunner.class)
@PrepareForTest({ SSLContext.class })
public class ATest {
@Test
public void testSomeMethod() throws Exception {
PowerMockito.mockStatic(SSLContext.class);
SSLContext context = Mockito.mock(SSLContext.class);
Mockito.when(context.getInstance("SSL")).thenReturn(context);
new AClass().someMethod();
}
}
JUnit 失败并显示以下堆栈跟踪:
java.lang.NullPointerException
at javax.net.ssl.SSLContext.init(Unknown Source)
at random.AClass.someMethod(AClass.java:8)
at random.ATest.testSomeMethod(ATest.java:20)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(Unknown Source)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(Unknown Source)
at java.lang.reflect.Method.invoke(Unknown Source)
at org.junit.internal.runners.TestMethod.invoke(TestMethod.java:68)
at org.powermock.modules.junit4.internal.impl.PowerMockJUnit44RunnerDelegateImpl$PowerMockJUnit44MethodRunner.runTestMethod(PowerMockJUnit44RunnerDelegateImpl.java:316)
at org.junit.internal.runners.MethodRoadie.run(MethodRoadie.java:89)
at org.junit.internal.runners.MethodRoadie.runBeforesThenTestThenAfters(MethodRoadie.java:97)
at org.powermock.modules.junit4.internal.impl.PowerMockJUnit44RunnerDelegateImpl$PowerMockJUnit44MethodRunner.executeTest(PowerMockJUnit44RunnerDelegateImpl.java:300)
at org.powermock.modules.junit4.internal.impl.PowerMockJUnit47RunnerDelegateImpl$PowerMockJUnit47MethodRunner.executeTestInSuper(PowerMockJUnit47RunnerDelegateImpl.java:131)
at org.powermock.modules.junit4.internal.impl.PowerMockJUnit47RunnerDelegateImpl$PowerMockJUnit47MethodRunner.access0(PowerMockJUnit47RunnerDelegateImpl.java:59)
at org.powermock.modules.junit4.internal.impl.PowerMockJUnit47RunnerDelegateImpl$PowerMockJUnit47MethodRunner$TestExecutorStatement.evaluate(PowerMockJUnit47RunnerDelegateImpl.java:147)
at org.powermock.modules.junit4.internal.impl.PowerMockJUnit47RunnerDelegateImpl$PowerMockJUnit47MethodRunner.evaluateStatement(PowerMockJUnit47RunnerDelegateImpl.java:107)
at org.powermock.modules.junit4.internal.impl.PowerMockJUnit47RunnerDelegateImpl$PowerMockJUnit47MethodRunner.executeTest(PowerMockJUnit47RunnerDelegateImpl.java:82)
at org.powermock.modules.junit4.internal.impl.PowerMockJUnit44RunnerDelegateImpl$PowerMockJUnit44MethodRunner.runBeforesThenTestThenAfters(PowerMockJUnit44RunnerDelegateImpl.java:288)
at org.junit.internal.runners.MethodRoadie.runTest(MethodRoadie.java:87)
at org.junit.internal.runners.MethodRoadie.run(MethodRoadie.java:50)
at org.powermock.modules.junit4.internal.impl.PowerMockJUnit44RunnerDelegateImpl.invokeTestMethod(PowerMockJUnit44RunnerDelegateImpl.java:208)
at org.powermock.modules.junit4.internal.impl.PowerMockJUnit44RunnerDelegateImpl.runMethods(PowerMockJUnit44RunnerDelegateImpl.java:147)
at org.powermock.modules.junit4.internal.impl.PowerMockJUnit44RunnerDelegateImpl.run(PowerMockJUnit44RunnerDelegateImpl.java:121)
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:123)
at org.powermock.modules.junit4.common.internal.impl.JUnit4TestSuiteChunkerImpl.run(JUnit4TestSuiteChunkerImpl.java:121)
at org.powermock.modules.junit4.common.internal.impl.AbstractCommonPowerMockRunner.run(AbstractCommonPowerMockRunner.java:53)
at org.powermock.modules.junit4.PowerMockRunner.run(PowerMockRunner.java:59)
at org.eclipse.jdt.internal.junit4.runner.JUnit4TestReference.run(JUnit4TestReference.java:86)
at org.eclipse.jdt.internal.junit.runner.TestExecution.run(TestExecution.java:38)
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:459)
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:675)
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.run(RemoteTestRunner.java:382)
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.main(RemoteTestRunner.java:192)
堆栈跟踪指向带有空指针的 context.init(null, null, null);
行。但是当我调试时(在 Eclipse 中),我可以清楚地看到 context
变量的值是 Mock for SSLContext, hashCode: 1857173583
。如果是模拟,那么像 init()
这样的 void 方法不应该做任何事情。那么,为什么它会抛出 NullPointerException
?
正在查看 API and decompiled signature for the init
method which throws the NPE
, it shows as final, which basic Mockito.mock() can not handle。
另一方面,PowerMockito.mock()
的 javadoc 为:
org.powermock.api.mockito.PowerMockito
public static T mock(Class type)
Creates a mock object that supports mocking of final and native methods.
Type Parameters:
T - the type of the mock object
Parameters:
type - the type of the mock object
Returns:
the mock object.
所以,稍微改变一下您的测试应该可以正常工作:
@RunWith(PowerMockRunner.class)
@PrepareForTest({SSLContext.class})
public class ATest {
@Test
public void testSomeMethod() throws Exception {
// create the mock to return by getInstance()
SSLContext context = PowerMockito.mock(SSLContext.class);
// mock the static method getInstance() to return above created mock context
PowerMockito.mockStatic(SSLContext.class);
Mockito.when(SSLContext.getInstance("SSL")).thenReturn(context);
// invoke the object under test
new AClass().someMethod();
//TODO - add verifications / assertions
}
}
更新:
因为你是运行测试PowerMockRunner
,你也可以替换
SSLContext context = PowerMockito.mock(SSLContext.class);
有一个字段
@Mock
private SSLContext context;
这也将由 PowerMock 处理(或者如果您只需要基本的 mockito,则使用 MockitoJUnitRunner
)
我有以下简单的 class: 导入 javax.net.ssl.SSLContext;
public class AClass {
public void someMethod() throws Exception {
SSLContext context = SSLContext.getInstance("SSL");
context.init(null, null, null);
}
}
及其 JUnit: 导入 javax.net.ssl.SSLContext;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.Mockito;
import org.powermock.api.mockito.PowerMockito;
import org.powermock.core.classloader.annotations.PrepareForTest;
import org.powermock.modules.junit4.PowerMockRunner;
@RunWith(PowerMockRunner.class)
@PrepareForTest({ SSLContext.class })
public class ATest {
@Test
public void testSomeMethod() throws Exception {
PowerMockito.mockStatic(SSLContext.class);
SSLContext context = Mockito.mock(SSLContext.class);
Mockito.when(context.getInstance("SSL")).thenReturn(context);
new AClass().someMethod();
}
}
JUnit 失败并显示以下堆栈跟踪:
java.lang.NullPointerException
at javax.net.ssl.SSLContext.init(Unknown Source)
at random.AClass.someMethod(AClass.java:8)
at random.ATest.testSomeMethod(ATest.java:20)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(Unknown Source)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(Unknown Source)
at java.lang.reflect.Method.invoke(Unknown Source)
at org.junit.internal.runners.TestMethod.invoke(TestMethod.java:68)
at org.powermock.modules.junit4.internal.impl.PowerMockJUnit44RunnerDelegateImpl$PowerMockJUnit44MethodRunner.runTestMethod(PowerMockJUnit44RunnerDelegateImpl.java:316)
at org.junit.internal.runners.MethodRoadie.run(MethodRoadie.java:89)
at org.junit.internal.runners.MethodRoadie.runBeforesThenTestThenAfters(MethodRoadie.java:97)
at org.powermock.modules.junit4.internal.impl.PowerMockJUnit44RunnerDelegateImpl$PowerMockJUnit44MethodRunner.executeTest(PowerMockJUnit44RunnerDelegateImpl.java:300)
at org.powermock.modules.junit4.internal.impl.PowerMockJUnit47RunnerDelegateImpl$PowerMockJUnit47MethodRunner.executeTestInSuper(PowerMockJUnit47RunnerDelegateImpl.java:131)
at org.powermock.modules.junit4.internal.impl.PowerMockJUnit47RunnerDelegateImpl$PowerMockJUnit47MethodRunner.access0(PowerMockJUnit47RunnerDelegateImpl.java:59)
at org.powermock.modules.junit4.internal.impl.PowerMockJUnit47RunnerDelegateImpl$PowerMockJUnit47MethodRunner$TestExecutorStatement.evaluate(PowerMockJUnit47RunnerDelegateImpl.java:147)
at org.powermock.modules.junit4.internal.impl.PowerMockJUnit47RunnerDelegateImpl$PowerMockJUnit47MethodRunner.evaluateStatement(PowerMockJUnit47RunnerDelegateImpl.java:107)
at org.powermock.modules.junit4.internal.impl.PowerMockJUnit47RunnerDelegateImpl$PowerMockJUnit47MethodRunner.executeTest(PowerMockJUnit47RunnerDelegateImpl.java:82)
at org.powermock.modules.junit4.internal.impl.PowerMockJUnit44RunnerDelegateImpl$PowerMockJUnit44MethodRunner.runBeforesThenTestThenAfters(PowerMockJUnit44RunnerDelegateImpl.java:288)
at org.junit.internal.runners.MethodRoadie.runTest(MethodRoadie.java:87)
at org.junit.internal.runners.MethodRoadie.run(MethodRoadie.java:50)
at org.powermock.modules.junit4.internal.impl.PowerMockJUnit44RunnerDelegateImpl.invokeTestMethod(PowerMockJUnit44RunnerDelegateImpl.java:208)
at org.powermock.modules.junit4.internal.impl.PowerMockJUnit44RunnerDelegateImpl.runMethods(PowerMockJUnit44RunnerDelegateImpl.java:147)
at org.powermock.modules.junit4.internal.impl.PowerMockJUnit44RunnerDelegateImpl.run(PowerMockJUnit44RunnerDelegateImpl.java:121)
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:123)
at org.powermock.modules.junit4.common.internal.impl.JUnit4TestSuiteChunkerImpl.run(JUnit4TestSuiteChunkerImpl.java:121)
at org.powermock.modules.junit4.common.internal.impl.AbstractCommonPowerMockRunner.run(AbstractCommonPowerMockRunner.java:53)
at org.powermock.modules.junit4.PowerMockRunner.run(PowerMockRunner.java:59)
at org.eclipse.jdt.internal.junit4.runner.JUnit4TestReference.run(JUnit4TestReference.java:86)
at org.eclipse.jdt.internal.junit.runner.TestExecution.run(TestExecution.java:38)
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:459)
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:675)
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.run(RemoteTestRunner.java:382)
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.main(RemoteTestRunner.java:192)
堆栈跟踪指向带有空指针的 context.init(null, null, null);
行。但是当我调试时(在 Eclipse 中),我可以清楚地看到 context
变量的值是 Mock for SSLContext, hashCode: 1857173583
。如果是模拟,那么像 init()
这样的 void 方法不应该做任何事情。那么,为什么它会抛出 NullPointerException
?
正在查看 API and decompiled signature for the init
method which throws the NPE
, it shows as final, which basic Mockito.mock() can not handle。
另一方面,PowerMockito.mock()
的 javadoc 为:
org.powermock.api.mockito.PowerMockito
public static T mock(Class type)
Creates a mock object that supports mocking of final and native methods.
Type Parameters:
T - the type of the mock object
Parameters:
type - the type of the mock object
Returns:
the mock object.
所以,稍微改变一下您的测试应该可以正常工作:
@RunWith(PowerMockRunner.class)
@PrepareForTest({SSLContext.class})
public class ATest {
@Test
public void testSomeMethod() throws Exception {
// create the mock to return by getInstance()
SSLContext context = PowerMockito.mock(SSLContext.class);
// mock the static method getInstance() to return above created mock context
PowerMockito.mockStatic(SSLContext.class);
Mockito.when(SSLContext.getInstance("SSL")).thenReturn(context);
// invoke the object under test
new AClass().someMethod();
//TODO - add verifications / assertions
}
}
更新:
因为你是运行测试PowerMockRunner
,你也可以替换
SSLContext context = PowerMockito.mock(SSLContext.class);
有一个字段
@Mock
private SSLContext context;
这也将由 PowerMock 处理(或者如果您只需要基本的 mockito,则使用 MockitoJUnitRunner
)