2016-11-17 73 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