2011-10-26 1 views
5

私はSpringで作成したカスタムイベントを単体テストしようとしていますが、興味深い問題が発生しています。 StaticApplicationContextを作成してBeanを手動で登録して配線すると、イベントをトリガーして、パブリッシャー(実装ApplicationEventPublisherAware)からリスナー(実装ApplicationListener<?>)までのプログラムフローを確認できます。私はSpringJunit4ClassRunner@ContextConfigurationすべてがApplicationEventsがリスナーに表示されないことを除いてうまく機能使用してコンテキストを作成するためのJUnitテストを作成しようとするとユニットテストSpring ApplicationEvents - イベントは公開されていますが、リスナーは起動していませんか?

しかし、(私は彼らが公表なっていることを確認しました)。

ApplicationEventsが正しく動作するようにコンテキストを作成する他の方法はありますか?私はSpringイベントフレームワークの単体テストについて、Web上ではあまり見つけていません。

+2

:私のApplicationListener<ContextClosedEvent>はカサンドラ接続を閉じた場合、私はチェックするために必要なていました –

答えて

1

テストクラスが登録されておらず、イベントパブリッシャーであるSpringアプリケーションコンテキストから解決されたため、イベントは発生しません。

私は、BeanとしてSpringに登録され、テストの一部として解決された別のクラスでイベントが処理される場合の回避策を実装しました。それはかなりではありませんが、より良い解決策を見つけるために一日の最善の部分を無駄にした後、私はこれで今、満足しています。

私のユースケースは、RabbitMQコンシューマ内でメッセージを受信したときにイベントを発生させていました。なお、以下で構成されている:

ラッパークラス

注テスト

内容器から解決した後、コールバック関数に渡すテストから呼び出され は、init()関数
public class TestEventListenerWrapper { 

CountDownLatch countDownLatch; 
TestEventWrapperCallbackFunction testEventWrapperCallbackFunction; 

public TestEventListenerWrapper(){ 

} 

public void Init(CountDownLatch countDownLatch, TestEventWrapperCallbackFunction testEventWrapperCallbackFunction){ 

    this.countDownLatch = countDownLatch; 
    this.testEventWrapperCallbackFunction = testEventWrapperCallbackFunction; 
} 

@EventListener 
public void onApplicationEvent(MyEventType1 event) { 

    testEventWrapperCallbackFunction.CallbackOnEventFired(event); 
    countDownLatch.countDown(); 
} 

@EventListener 
public void onApplicationEvent(MyEventType2 event) { 

    testEventWrapperCallbackFunction.CallbackOnEventFired(event); 
    countDownLatch.countDown(); 
} 

@EventListener 
public void onApplicationEvent(OnQueueMessageReceived event) { 

    testEventWrapperCallbackFunction.CallbackOnEventFired(event); 
    countDownLatch.countDown(); 
} 
} 

コールバックインタフェース

public interface TestEventWrapperCallbackFunction { 

void CallbackOnEventFired(ApplicationEvent event); 
} 

ユニット構成テストで参照されるBeanを定義するテスト構成クラス。これが有用である前に、それが最後に

@Configuration 
public class TestContextConfiguration { 
    @Lazy 
    @Bean(name="testEventListenerWrapper") 
    public TestEventListenerWrapper testEventListenerWrapper(){ 
     return new TestEventListenerWrapper(); 
    } 
} 

、のApplicationContextから豆を解決し、初期の(呼び出しユニットテスト自体)(次のステップを参照)のApplicationContextから分離し、initialsedする必要がありますは、アサーション基準を渡す関数です(これは、Beanをシングルトンとして登録していることを前提としています。これは、SpringのapplicationContextのデフォルトです)。コールバック関数はここで定義され、Init()にも渡されます。

@ContextConfiguration(classes= {TestContextConfiguration.class, 
           //..., - other config classes 
           //..., - other config classes 
           }) 
public class QueueListenerUnitTests 
     extends AbstractTestNGSpringContextTests { 

    private MessageProcessorManager mockedMessageProcessorManager; 
    private ChannelAwareMessageListener queueListener; 

    private OnQueueMessageReceived currentEvent; 

    @BeforeTest 
    public void Startup() throws Exception { 

     this.springTestContextPrepareTestInstance(); 
     queueListener = new QueueListenerImpl(mockedMessageProcessorManager); 
     ((QueueListenerImpl) queueListener).setApplicationEventPublisher(this.applicationContext); 
     currentEvent = null; 
    } 

    @Test 
    public void HandleMessageReceived_QueueMessageReceivedEventFires_WhenValidMessageIsReceived() throws Exception { 

     //Arrange 
     //Other arrange logic 
     Channel mockedRabbitmqChannel = CreateMockRabbitmqChannel(); 
     CountDownLatch countDownLatch = new CountDownLatch(1); 

     TestEventWrapperCallbackFunction testEventWrapperCallbackFunction = (ev) -> CallbackOnEventFired(ev); 
     TestEventListenerWrapper testEventListenerWrapper = (TestEventListenerWrapper)applicationContext.getBean("testEventWrapperOnQueueMessageReceived"); 
     testEventListenerWrapper.Init(countDownLatch, testEventWrapperCallbackFunction); 

     //Act 
     queueListener.onMessage(message, mockedRabbitmqChannel); 
     long awaitTimeoutInMs = 1000; 
     countDownLatch.await(awaitTimeoutInMs, TimeUnit.MILLISECONDS); 

     //Assert - assertion goes here 
    } 

    //The callback function that passes the event back here so it can be made available to the tests for assertion 
    private void CallbackOnEventFired(ApplicationEvent event){ 
     currentEvent = (OnQueueMessageReceived)event; 
    } 
} 
  • EDIT 1:上記は異なるアプローチで更新されましたので、アサーションは、テストに失敗しませんでした**
  • :サンプルコードはたCountDownLatch
  • EDIT 2で更新されました
0

コンテキストを手動で作成できます。例えば

:この質問には答えがない理由

@Test 
public void testSpringShutdownHookForCassandra(){ 
    ConfigurableApplicationContext ctx = new AnnotationConfigApplicationContext(CassandraConfig.class); 

    CassandraConnectionManager connectionManager = ctx.getBean(CassandraConnectionManager.class); 
    Session session = connectionManager.openSession(testKeySpaceName); 

    Assert.assertFalse(session.isClosed()); 
    ctx.close(); 

    Assert.assertTrue(session.isClosed()); 
} 
関連する問題