2016-07-11 4 views
1

У меня есть следующий простой класс: import javax.net.ssl.SSLContext;SSLContext mock не работает как ожидалось

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$2.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.access$100(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$1.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. Если макет, то метод void, такой как init(), ничего не должен делать. Итак, почему он бросает NullPointerException?

ответ

2

Глядя на API и декомпилируемой подписи для init метода, который бросает NPE, он показывает, как окончательного, что основной Mockito.mock() can not handle.

Final method

С другой стороны, Javadoc для PowerMockito.mock() гласит:

org.powermock.api.mockito.PowerMockito

общественность статической Т макет (тип класса)
Создает фиктивный объект, который поддерживает Осмеяние окончательного и собственные методы.

Тип Параметры:
        T - тип макете объекта
Параметры:
        тип - тип макете объекта
Возвращает:
        макет объект.

Таким образом, изменение чуток тест должен заставить его работать:

@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 
    } 
} 

Update:

Поскольку вы запускаете тест с PowerMockRunner, вы также можно заменить

SSLContext context = PowerMockito.mock(SSLContext.class); 

с полем

@Mock 
private SSLContext context; 

, которые также будут обработаны PowerMock (или использовать MockitoJUnitRunner, если вам просто нужно основной Mockito)

+0

Всегда думал, что 'PowerMockito.mock()' '& Mockito.mock () 'были одинаковыми. Спасибо, что указали! – Vineet

+1

@ Vineet не проблема, действительно, они [аналогичные] (http://i.imgur.com/pIvKZxD.gif), причем powermock добавляет еще несколько функций поверх mockito. Также я обновил ответ со вторым подходом. – Morfic