2012-01-30 65 views
3

我正在嘲笑(使用Mockito)DefaultMessageListenerContainerorg.springframework.jms.listener.DefaultMessageListenerContainer)。这里是我的代码:如何模拟DefaultMessageListenerContainer

@Mock 
private DefaultMessageListenerContainer defaultMessageListenerContainer; 

@Before 
public void init() { 

    MockitoAnnotations.initMocks(this); 
    incomingFeedController = new IncomingFeedControllerImpl(); 

} 

@Test 
public void testHandleConnectionState() { 
    List<DefaultMessageListenerContainer> listeners = 
     new ArrayList<DefaultMessageListenerContainer>(); 
    listeners.add(defaultMessageListenerContainer); 
    incomingFeedController.setContainers(listeners); 
    when(defaultMessageListenerContainer.isRunning()).thenReturn(false); 
} 

然后我希望做像一些适当的测试:

when(defaultMessageListenerContainer.isRunning()).thenReturn(false); 

但JUnit的后运行这条线就结了:

 
java.lang.NullPointerException 
    at org.springframework.jms.listener.AbstractJmsListeningContainer.isRunning(AbstractJmsListeningContainer.java:312) 
    at com.source.etf.manager.integrationgateway.feedcontroller.IncomingFeedControllerTest.testHandleConnectionState(IncomingFeedControllerTest.java:37) 
    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:59) 
    at org.junit.internal.runners.MethodRoadie.runTestMethod(MethodRoadie.java:98) 
    at org.junit.internal.runners.MethodRoadie$2.run(MethodRoadie.java:79) 
    at org.junit.internal.runners.MethodRoadie.runBeforesThenTestThenAfters(MethodRoadie.java:87) 
    at org.junit.internal.runners.MethodRoadie.runTest(MethodRoadie.java:77) 
    at org.junit.internal.runners.MethodRoadie.run(MethodRoadie.java:42) 
    at org.junit.internal.runners.JUnit4ClassRunner.invokeTestMethod(JUnit4ClassRunner.java:88) 
    at org.junit.internal.runners.JUnit4ClassRunner.runMethods(JUnit4ClassRunner.java:51) 
    at org.junit.internal.runners.JUnit4ClassRunner$1.run(JUnit4ClassRunner.java:44) 
    at org.junit.internal.runners.ClassRoadie.runUnprotected(ClassRoadie.java:27) 
    at org.junit.internal.runners.ClassRoadie.runProtected(ClassRoadie.java:37) 
    at org.junit.internal.runners.JUnit4ClassRunner.run(JUnit4ClassRunner.java:42) 
    at org.eclipse.jdt.internal.junit4.runner.JUnit4TestReference.run(JUnit4TestReference.java:50) 
    at org.eclipse.jdt.internal.junit.runner.TestExecution.run(TestExecution.java:38) 
    at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:467) 
    at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:683) 
    at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.run(RemoteTestRunner.java:390) 
    at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.main(RemoteTestRunner.java:197) 

我还检查AbstractJmsListeningContainer这里是NPE发生的代码:

public final boolean isRunning() { 
    synchronized (this.lifecycleMonitor) { 
     return (this.running && runningAllowed()); 
    } 
} 

我发现的是lifecycleMonitor对象没有被实例化。这个对象是刚刚在顶部宣布AbstractJmsListeningContainer

protected final Object lifecycleMonitor = new Object(); 

不知道如何正确地嘲笑DefaultMessageListenerContainer

+0

类似的问题:http://stackoverflow.com/questions/2457239/injecting-mockito-mocks-into-a-spring-bean – 2012-01-30 16:52:11

+0

你为什么*要*嘲笑它?你的代码不应该依赖'DefaultMessageListenerContainer',它是一个Spring基础组件。 – skaffman 2012-01-31 16:19:59

回答

1

您仍然需要对正在初始化的对象设置模拟。

我看到您正在测试IncomingFeedControllerImpl,并且很可能您的模拟对象是此类实例的成员。因为你没有明确地在你的IncomingFeedControllerImpl上设置你的模拟DefaultMessageListenerContainer,所以AbstractJmsListeningContainer(这可能是@Autowired)仍然处于闲置状态,没有被模拟。

您将需要使用setter方法或构造函数注入它。 (你也可以@Autowired吧)

+0

没有。不是这种情况。试过了。这肯定与这个生命周期监视器没有实例化有关。 – szymon 2012-01-30 17:11:44

+0

好吧,根据你的代码,你试图模拟你的'DefaultMessageListenerContainer',并通过接收'AbstractJmsListeningContainer',意味着你的'IncomingFeedController'上从来没有设置模拟对象。 – 2012-01-30 17:15:35

+0

我只是中省略这一部分,但这里是我的测试代码: '@Test 公共无效testHandleConnectionState(){ 名单<使用DefaultMessageListenerContainer>听众=新的ArrayList <使用DefaultMessageListenerContainer>(); listeners.add(defaultMessageListenerContainer); incomingFeedController.setContainers(listeners); when(defaultMessageListenerContainer.isRunning()).thenReturn(false);' – szymon 2012-01-30 17:18:38

1

Mockito不能模拟最后的类或最终的方法。这些约束由JVM本身执行。嘲笑这样的代码将会要求重写类字节码并将其加载到另一个类加载器中。这导致非常复杂的代码; PowerMock进入了这个方向,代码难以维护。

也不要模拟你不拥有的类型,请参阅google上的4-5首个结果。为什么你需要在单元测试中模拟Spring类型。您应该创建一些间接方法来避免Spring依从性或编写集成测试;后者似乎更合适,因为它与JMS有关。

0

您将需要使用PowerMock,或者按照@Brice的建议进行集成测试。以下是如何做到这一点的PowerMock:

@RunWith(PowerMockRunner.class) 
@PrepareForTest(DefaultMessageListenerContainer.class) 
public class MyTestClass { 

    // cannot use the @Mock annotation 
    private DefaultMessageListenerContainer defaultMessageListenerContainer; 

    @Before 
    public void init() { 
     // This should allow the mocking of final methods as well. 
     defaultMessageListenerContainer = 
      PowerMockito.mock(DefaultMessageListenerContainer.class); 
     incomingFeedController = new IncomingFeedControllerImpl(); 

    } 

    @Test 
    public void testHandleConnectionState() { 
     List<DefaultMessageListenerContainer> listeners = 
      new ArrayList<DefaultMessageListenerContainer>(); 
     listeners.add(defaultMessageListenerContainer); 
     incomingFeedController.setContainers(listeners); 
     when(defaultMessageListenerContainer.isRunning()).thenReturn(false); 
    } 

} 
+0

是的'@ PrepareForTest'指令是强制性的,否则PowerMock不会在暂时的PowerMock类加载器的领域_prepare_这个类 – Brice 2012-01-31 08:44:25

+0

编辑以反映这一点。 – jhericks 2012-01-31 16:03:41

0
private DefaultMessageListenerContainer createFailingContainer() { 
    DefaultMessageListenerContainer container = new DefaultMessageListenerContainer() { 
     @Override 
     public void start() throws JmsException { 
      throw new MyJmsException("TEST"); 
     } 

     @Override 
     public void stop() throws JmsException { 
      throw new MyJmsException("TEST"); 
     } 
    }; 
    return container; 
} 

class MyJmsException extends JmsException { 
    private static final long serialVersionUID = 1L; 

    public MyJmsException(String msg) { 
     super(msg); 
    } 
}