2017-12-30 10 views
1

私はユニットテストにJUnitのからJUnitのバネJMSリスナー

@Component 
public class NotificationReader { 

    @JmsListener(destination = "myAppQ") 
    public void receiveMessage(NotificationMessage notificationMessage) { 
     System.out.println("Received <" + notificationMessage.getStaffNumber() + ">"); 
    } 

} 

以下の単純なJMSリスナーコードをしたい、私は、Active MQにメッセージをポンプするためにjmsTemplateを使用しています。

jmsリスナーが呼び出されたかどうかをテストします。

How to wait for @JMSListener annotated method to complete in JUnitのようないくつかの解決策(カウンターを使用)を見ましたが、私がやりたくないテスト目的のためにリスナーコードを実際に変更しています。

他の方法はありますか?


回答で示唆されているように設定を試してみてください。

@RunWith(SpringRunner.class) 
@SpringBootTest 
public class TestNotificationReader { 

    @Autowired 
    JmsTemplate jmsTemplate; 

    @Value("${outbound.endpoint}") 
    private String destination; 

    @Test 
    public void contextLoads() { 
    } 

    @Test 
    public void testPutToQ() { 
     NotificationMessage notificationMessage = new NotificationMessage(); 
     notificationMessage.setStaffNumber("100"); 
     notificationMessage.setWorkflowType("TYPE"); 
     notificationMessage.setWorkflowId("100"); 
     notificationMessage.setWorkflowDescription("Test From Queue"); 
     jmsTemplate.convertAndSend(destination, notificationMessage); 

     jmsTemplate.setReceiveTimeout(10000); 

     try { 
      TestConfig.latch.await(10, TimeUnit.SECONDS); 

      NotificationMessage temp = (NotificationMessage) TestConfig.received; 

      System.out.println(" temp.getStaffNumber() " + temp.getStaffNumber()); 
     } catch (InterruptedException e) { 
      // TODO Auto-generated catch block 
      e.printStackTrace(); 
     } 
    } 

    @Configuration 
    public static class TestConfig { 

     private static final CountDownLatch latch = new CountDownLatch(1); 

     private static Object received; 

     @Bean 
     public static BeanPostProcessor listenerWrapper() { 
      return new BeanPostProcessor() { 

       @Override 
       public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException { 
        if (bean instanceof NotificationReader) { 
         MethodInterceptor interceptor = new MethodInterceptor() { 

          @Override 
          public Object invoke(MethodInvocation invocation) throws Throwable { 
           Object result = invocation.proceed(); 
           if (invocation.getMethod().getName().equals("receiveMessage")) { 
            received = invocation.getArguments()[0]; 
            latch.countDown(); 
           } 
           return result; 
          } 

         }; 
         if (AopUtils.isAopProxy(bean)) { 
          ((Advised) bean).addAdvice(interceptor); 
          return bean; 
         } else { 
          ProxyFactory proxyFactory = new ProxyFactory(bean); 
          proxyFactory.addAdvice(interceptor); 
          return proxyFactory.getProxy(); 
         } 
        } else { 
         return bean; 
        } 
       } 

       @Override 
       public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException { 
        // TODO Auto-generated method stub 
        return bean; 
       } 

      }; 
     } 

    } 

} 

私はtestConfigを追加すると、JMSTempateのオートワイヤリングは

Caused by: org.springframework.beans.factory.NoSuchBeanDefinitionException: No qualifying bean of type 'org.springframework.jms.core.JmsTemplate' available: expected at least 1 bean which qualifies as autowire candidate. Dependency annotations: {@org.springframework.beans.factory.annotation.Autowired(required=true)} 
    at org.springframework.beans.factory.support.DefaultListableBeanFactory.raiseNoMatchingBeanFound(DefaultListableBeanFactory.java:1493) ~[spring-beans-4.3.13.RELEASE.jar:4.3.13.RELEASE] 

答えて

2

は、(テストケース用)プロキシであなたのリスナーBeanをラップし、ラッチを使用して、受信したオブジェクトが何であることを確認失敗

@RunWith(SpringRunner.class) 
@SpringBootTest(classes = { So48033124Application.class, So48033124ApplicationTests.TestConfig.class }) 
public class So48033124ApplicationTests { 

    @Autowired 
    private JmsTemplate template; 

    @Test 
    public void test() throws Exception { 
     Foo foo = new Foo("bar"); 
     this.template.convertAndSend("foo", foo); 
     assertThat(TestConfig.latch.await(10, TimeUnit.SECONDS)).isTrue(); 
     assertThat(TestConfig.received).isEqualTo(foo); 
    } 

    @Configuration 
    public static class TestConfig { 

     private static final CountDownLatch latch = new CountDownLatch(1); 

     private static Object received; 

     @Bean 
     public static BeanPostProcessor listenerWrapper() { 
      return new BeanPostProcessor() { 

       @Override 
       public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException { 
        if (bean instanceof MyListener) { 
         MethodInterceptor interceptor = new MethodInterceptor() { 

          @Override 
          public Object invoke(MethodInvocation invocation) throws Throwable { 
           Object result = invocation.proceed(); 
           if (invocation.getMethod().getName().equals("listen")) { 
            received = invocation.getArguments()[0]; 
            latch.countDown(); 
           } 
           return result; 
          } 

         }; 
         if (AopUtils.isAopProxy(bean)) { 
          ((Advised) bean).addAdvice(interceptor); 
          return bean; 
         } 
         else { 
          ProxyFactory proxyFactory = new ProxyFactory(bean); 
          proxyFactory.addAdvice(interceptor); 
          return proxyFactory.getProxy(); 
         } 
        } 
        else { 
         return bean; 
        } 
       } 

      }; 
     } 

    } 

} 

EDIT ...期待

上記はSpring Framework 5以降をベースにしており、Java 8を使用しており、両方ともBeanPostProcessorメソッドのデフォルト実装を提供しています。

あなたは春の以前のバージョンを使用している場合も、BPPがあまりにもstaticあるべき

@Override 
public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException { 
    return bean; 
} 

が必要になります。

+0

BeanPostProcessor()がpostProcessBeforeInitializationを実装しなければならなかったので、このコードをコンパイルできませんでした。この設定を使用すると、既存のBeanの自動配線に失敗したためにコンテキスト・ロードが失敗します。上に提供されているものとは別のコードが必要かどうかをよく確認してください。 – lives

+0

この例はSpring 5.0に基づいています。私の編集を参照してください。もう何も必要ありません。 BPPを静的に宣言してリスナーBeanの前に登録されていることを確認する必要があります。それでも問題が解決しない場合は、質問を編集してCOMPLETE設定とテストを表示してください。 –

+0

あなたの応答を感謝します。私はまだそれを動作させることができませんでした。私はjunitのテストコードを投稿しました – lives

関連する問題