2016-04-10 20 views
2

私は当社の既存の春のJUnitテストで@TransactionalEventsをテストするために(春4.2 https://spring.io/blog/2015/02/11/better-application-events-in-spring-framework-4-2の機能を)しようとしてきた(@TransactionalTestExecutionListenerまたはサブクラスAbstractTransactionalUnit4SpringContextTestsのいずれかを介して実行しますが、強制選択がありますように思えます - 。 - @Rollback注釈なしでテストを実行するか、イベントは発生しません。どちらか誰もがテストを@Rollbackできる一方@TransactionalEventsをテストする良い方法渡って来たテスト@TransactionalEventsと@Rollback

+0

:-)魔法のように動作します。この方法でコミット時に呼び出されます、あなたは恥ずかしがり屋別の方法でテストしてください。私はおそらくあなた自身のコードではなく、フレームワークをテストしていると主張したいと思います。 –

+0

私は同意するかどうかわかりませんが、私はそれを考えます。 @Rollbackは、初期テスト状態に戻るようにデータベースをリセットすることです(テストが相互に作用する可能性が低いことを確認するため)。 – adam

+0

私はそれが何をしているか知っています。問題は、トランザクションがコミットしたというイベントを取得するよう求めていることです。それはありません。 –

答えて

3

ステファン・ニコルが正しい:TransactionPhaseのためか? @TransactionalEventListenerAFTER_COMMITに設定されている場合、自動ロールバックセマンティクスを使用したトランザクションテストでは意味をなさない発砲した。

つまり、トランザクションがコミットされていない場合、そのトランザクションがコミットされていない場合、イベントを起動させる方法はありません。

実際にイベントを発生させるには、トランザクションをコミットする必要があります(たとえば、テストメソッドに@Commitと注釈を付ける)。コミット後にクリーンアップするには、トランザクションがコミットされたの後に、モードで@Sqlを使用してクリーンアップスクリプトを実行するモードを使用できるようにする必要があります。例えば、次の(未テストコード)のようなものは、あなたのために働くかもしれない:

@Transactional 
@Commit 
@Sql(scripts = "/cleanup.sql", executionPhase = AFTER_TEST_METHOD, 
    config = @SqlConfig(transactionMode = TransactionMode.ISOLATED)) 
@Test 
public void test() { /* ... */ } 

よろしく、

サム(春TestContextフレームワーク著者)

+0

ありがとう、ありがとう。私はこの作業をしてきたので、私の理解の一部は、伝播に関係なくネストされた\ @Transactionalコールは、最高の\ @ Transactionalメソッドが完了するまでイベントを保持するということです。 – adam

1

サムBrannenのソリューションがほとんどで動作しますアダムのコメントについて。

実際には、@TransactionalEventListenerと注釈されたメソッドは、テストメソッドのトランザクションがコミットされた後に呼び出されます。これは、イベントを発生させる呼び出しメソッドが、物理トランザクションではなく論理トランザクション内で実行されているためです。

代わりに、新しい物理トランザクション内で呼び出しメソッドが実行されると、@TransactionalEventListenerで注釈が付けられたメソッドが適切なタイミングで、つまりテストメソッドのトランザクションがコミットされる前に呼び出されます。

また、これらのトランザクションについて実際には気にしないので、テストメソッドには@Commitは必要ありません。しかし、呼び出しメソッドのコミットされた変更を取り消すには、Sam Brannenが説明した@Sql(...)ステートメントが必要です。

下記の小さな例を参照してください。トランザクションがコミットされたとき(@TransactionalEventListenerのデフォルトの動作)と呼ばれているリスナー

まず:

@Component 
public class MyListener { 

    @TransactionalEventListener 
    public void when(MyEvent event) { 
     ... 
    } 
} 

はその後、イベントを発行したアプリケーションサービスは、上記のクラスでに耳を傾け。(詳細については Spring Framework docを参照)トランザクションがメソッドが呼び出されるたびに新しい物理的なものであるように構成されていることに注意してください:

@Service 
@Transactional(propagation = Propagation.REQUIRES_NEW) 
public class MyApplicationService { 

    public void doSomething() { 
     // ... 
     // publishes an instance of MyEvent 
     // ... 
    } 
} 

最後試験方法サムBrannenによってではなく、@Commit注釈なしに提案されているようにこの時点で、必要に応じて:あなたは、あなたのテストを使用するトランザクションをロールバックし、コードの確認特定の作品を作りたい場合は

@Transactional 
@Sql(scripts = "/cleanup.sql", executionPhase = AFTER_TEST_METHOD, 
    config = @SqlConfig(transactionMode = TransactionMode.ISOLATED)) 
@Test 
public void test() { 
    MyApplicationService target = // ... 
    target.doSomething(); 
    // the event is now received by MyListener 
    // assertions on the side effects of MyListener 
    // ... 
} 

それは

関連する問題