2017-12-30 16 views
1

나는, 내가 액티브 MQ에 메시지를 펌프이 JmsTemplate을 사용하고 단위 테스트에의 JUnit에서의 JUnit 스프링 JMS 리스너

@Component 
public class NotificationReader { 

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

} 

아래 간단한 JMS 리스너 코드를합니다.

jms 수신기가 호출되었는지 테스트하고 싶습니다.

How to wait for @JMSListener annotated method to complete in JUnit과 같은 몇 가지 솔루션 (카운터 사용)을 보았습니다.이 솔루션은 실제로 수행하려는 테스트 목적을 위해 리스너 코드를 실제로 변경합니다.

다른 대안이 있습니까?


답변에 제안 된대로 구성을 시도했습니다. 나는 testConfig을 추가하면

@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; 
       } 

      }; 
     } 

    } 

} 

의 JMSTempate의를 autowiring은

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

가 (테스트 케이스에 대한) 프록시에 리스너 콩을 싸서 래치를 사용하고받은 물체가 무엇인지 확인이 실패하면

@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; 
        } 
       } 

      }; 
     } 

    } 

} 

편집 ... 예상

위의 코드는 Java 8을 사용하는 Spring Framework 5 이상을 기반으로하며 BeanPostProcessor 메서드에 대한 기본 구현을 제공합니다.

당신이 봄의 이전 버전을 사용하는 경우 또한 BPP이 너무 static을해야

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

가 필요합니다.

+0

BeanPostProcessor()가 postProcessBeforeInitialization을 구현해야하므로이 코드를 컴파일 할 수 없습니다. 이 구성을 사용하면 기존 빈의 자동 연결 실패로 인해 컨텍스트로드가 실패합니다. 위에서 제공된 코드와 별도로 다른 코드가 필요한지 확인하십시오. – lives

+0

예제는 Spring 5.0을 기반으로합니다. 내 편집을 참조하십시오. 당신은 더 이상 아무것도 필요하지 않습니다. BPP를'static'으로 선언하여 리스너 빈 앞에 등록되어 있는지 확인해야합니다. 그래도 작동하지 않으면 질문을 편집하여 COMPLETE 구성 및 테스트를 표시하십시오. –

+0

당신의 대답을 감사하십시오. Gary Russel. 나는 아직도 그것을 작동하게 만들 수 없었다. 내 junit 테스트 코드를 게시했습니다 – lives