2016-11-17 163 views
2

測試方法調用時,我有這兩條線在單元測試:NullPointerException異常磕碰用的Mockito

DefaultMessageListenerContainer defaultMessageListenerContainer = Mockito.mock(DefaultMessageListenerContainer.class); 
when(defaultMessageListenerContainer.isRunning()).thenReturn(true); 

堆棧跟蹤:

java.lang.NullPointerException 
    at org.springframework.jms.listener.AbstractJmsListeningContainer.isRunning(AbstractJmsListeningContainer.java:347) 
    at xxxxxxxxxxxxxx.MessageProcessorControllerTest.testPing(MessageProcessorControllerTest.java:109) 
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) 
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62) 
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) 
    at java.lang.reflect.Method.invoke(Method.java:497) 
    at org.testng.internal.MethodInvocationHelper.invokeMethod(MethodInvocationHelper.java:85) 
    at org.testng.internal.Invoker.invokeMethod(Invoker.java:639) 
    at org.testng.internal.Invoker.invokeTestMethod(Invoker.java:816) 
    at org.testng.internal.Invoker.invokeTestMethods(Invoker.java:1124) 
    at org.testng.internal.TestMethodWorker.invokeTestMethods(TestMethodWorker.java:125) 
    at org.testng.internal.TestMethodWorker.run(TestMethodWorker.java:108) 
    at org.testng.TestRunner.privateRun(TestRunner.java:774) 
    at org.testng.TestRunner.run(TestRunner.java:624) 
    at org.testng.SuiteRunner.runTest(SuiteRunner.java:359) 
    at org.testng.SuiteRunner.runSequentially(SuiteRunner.java:354) 
    at org.testng.SuiteRunner.privateRun(SuiteRunner.java:312) 
    at org.testng.SuiteRunner.run(SuiteRunner.java:261) 
    at org.testng.SuiteRunnerWorker.runSuite(SuiteRunnerWorker.java:52) 
    at org.testng.SuiteRunnerWorker.run(SuiteRunnerWorker.java:86) 
    at org.testng.TestNG.runSuitesSequentially(TestNG.java:1191) 
    at org.testng.TestNG.runSuitesLocally(TestNG.java:1116) 
    at org.testng.TestNG.run(TestNG.java:1024) 
    at org.testng.IDEARemoteTestNG.run(IDEARemoteTestNG.java:72) 
    at org.testng.RemoteTestNGStarter.main(RemoteTestNGStarter.java:124) 

無論我做什麼,NPE是在when拋出就好像真正的方法在設置存根時被調用一樣。我正在使用mockito v1.10.19。我究竟做錯了什麼?

UPDATE: 下面是完整的獨立測試類:

import org.mockito.Mockito; 
import org.springframework.jms.listener.DefaultMessageListenerContainer; 
import org.testng.annotations.Test; 

import static org.mockito.Mockito.when; 

public class JmsTest { 
    @Test 
    public void test() throws Exception { 
     DefaultMessageListenerContainer defaultMessageListenerContainer = Mockito.mock(
       DefaultMessageListenerContainer.class); 
     when(defaultMessageListenerContainer.isRunning()).thenReturn(true); 
    } 
} 

,這是拋出的異常:

java.lang.NullPointerException 
    at org.springframework.jms.listener.AbstractJmsListeningContainer.isRunning(AbstractJmsListeningContainer.java:347) 
    at xxxxxxxxxxx.util.JmsTest.test(JmsTest.java:17) 
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) 
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62) 
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) 
    at java.lang.reflect.Method.invoke(Method.java:497) 
    at org.testng.internal.MethodInvocationHelper.invokeMethod(MethodInvocationHelper.java:85) 
    at org.testng.internal.Invoker.invokeMethod(Invoker.java:639) 
    at org.testng.internal.Invoker.invokeTestMethod(Invoker.java:816) 
    at org.testng.internal.Invoker.invokeTestMethods(Invoker.java:1124) 
    at org.testng.internal.TestMethodWorker.invokeTestMethods(TestMethodWorker.java:125) 
    at org.testng.internal.TestMethodWorker.run(TestMethodWorker.java:108) 
    at org.testng.TestRunner.privateRun(TestRunner.java:774) 
    at org.testng.TestRunner.run(TestRunner.java:624) 
    at org.testng.SuiteRunner.runTest(SuiteRunner.java:359) 
    at org.testng.SuiteRunner.runSequentially(SuiteRunner.java:354) 
    at org.testng.SuiteRunner.privateRun(SuiteRunner.java:312) 
    at org.testng.SuiteRunner.run(SuiteRunner.java:261) 
    at org.testng.SuiteRunnerWorker.runSuite(SuiteRunnerWorker.java:52) 
    at org.testng.SuiteRunnerWorker.run(SuiteRunnerWorker.java:86) 
    at org.testng.TestNG.runSuitesSequentially(TestNG.java:1191) 
    at org.testng.TestNG.runSuitesLocally(TestNG.java:1116) 
    at org.testng.TestNG.run(TestNG.java:1024) 
    at org.testng.IDEARemoteTestNG.run(IDEARemoteTestNG.java:72) 
    at org.testng.RemoteTestNGStarter.main(RemoteTestNGStarter.java:124) 
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) 
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62) 
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) 
    at java.lang.reflect.Method.invoke(Method.java:497) 
    at com.intellij.rt.execution.application.AppMain.main(AppMain.java:147) 
+1

你能告訴我們你的testPing方法嗎?還有任何'@ Before'或'@ BeforeClass'方法? –

+0

嘗試調試您的代碼。空指針不應該拋在「when」行上。它一定在別的地方。你能提供完整的測試類文件,以便我們可以將行號關聯起來嗎? –

回答

0

不使用你的defaultMessageListenerContainer之一。失敗的是AbstractJmsListeningContainer

您需要確保將模擬變量正確傳遞給您正在嘗試測試的類。

+1

改變代碼使用'AbstractJmsListeningContainer'產生相同的結果:'AbstractJmsListeningContainer使用DefaultMessageListenerContainer = Mockito.mock( \t \t \t \t AbstractJmsListeningContainer.class); \t \t when(defaultMessageListenerContainer.isRunning())。thenReturn(true);' – Mensur

+0

我添加了一個獨立的測試類來重現問題。請參閱我的更新。 – Mensur

0

這是一個很好的!我本來期待測試通過,因爲它似乎只是設定了期望,然後沒有斷言。我想我會把它留給一個Mockito專家,爲什麼那個看起來很簡單的練習不起作用。我當然有興趣知道它背後的原因。與此同時,如果它可能是您使用其他庫的選項,我將提供此建議,請嘗試使用JMockit。下面的內容應該與你正在試圖用Mockito實現的內容大致相當...但是測試通過了。祝你好運!

import mockit.Expectations; 
import mockit.Mocked; 
import org.junit.Test; 
import org.springframework.jms.listener.DefaultMessageListenerContainer; 

import static org.assertj.core.api.Assertions.assertThat; 

public class JmsTest2 { 

    @Mocked 
    DefaultMessageListenerContainer defaultMessageListenerContainer; 

    @Test 
    public void test() throws Exception { 
     new Expectations() {{ 
      defaultMessageListenerContainer.isRunning(); result = true; 
     }}; 
     assertThat(defaultMessageListenerContainer.isRunning()).isTrue(); 
    } 
} 

編輯1:

展望這個更貼切一點,似乎有在isRunning()方法的一些同步對象周圍打上決賽。 Mockito,AFAIK,在你想要改變標有final的對象的情況下,它們往往不是那麼有用。你可以試着用PowerMock來解決這個問題,或者使用一個不同的庫 - 我已經建議了我喜歡的那個 - 我認爲這對你來說是一個乾淨而簡單的方法。

protected final Object lifecycleMonitor = new Object(); 
... 
@Override 
public final boolean isRunning() { 
    synchronized (this.lifecycleMonitor) { 
     return (this.running && runningAllowed()); 
    } 
} 
+0

我也看到了。但我認爲Mockito不應該調用這個方法時間,所以它裏面的內容應該沒有關係。 – Mensur

+0

認爲這是一個很好的問題,因爲你的代碼清楚地表達了Mockito在協作類中可能實現的一切,這些協作類沒有受到使用「final」所施加的限制的束縛。基本上,你會發現自己想要完成Mockito的目標(除了關於不能處理最終方法的腳註外),但卻受到挫敗。直到我注意到你想要取代的方法是最終的,我想,哦,這應該工作。看起來像Mockito的更新版本應該能夠做到這一點。 – unigeek