簡體   English   中英

使用Mockito存根測試方法調用時發生NullPointerException

[英]NullPointerException when stubbing a test method call with 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)

不管我做什么,都會在上線when拋出NPE,就像在設置存根時調用了真正的方法一樣。 我正在使用Mockito v1.10.19。 我究竟做錯了什么?

更新:這是整個獨立測試類:

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)

您的defaultMessageListenerContainer不是正在使用的那個。 失敗的是類型AbstractJmsListeningContainer

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

那是一個好人! 我曾期望該測試能夠通過,因為它似乎只會設定期望值,而不會做出任何斷言。 我想我會把它交給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:

仔細研究一下,似乎在標記為final的對象的isRunning()方法中存在一些同步。 在您將要更改的對象標記為final的情況下,AFAIK的Mockito往往無濟於事。 您可以嘗試與PowerMock對抗,或者使用其他庫(我已經建議過我喜歡的庫),我認為這對您來說是一種干凈,簡單的方法。

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

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM