복붙노트

[SPRING] @ TransactionalEvents 및 @Rollback 테스트

SPRING

@ TransactionalEvents 및 @Rollback 테스트

나는 @TransactionalEvents (Spring 4.2의 기능인 https://spring.io/blog/2015/02/11/better-application-events-in-spring-framework-4-2)를 테스트하려고 노력 해왔다. 기존의 Spring JUnit 테스트 (@TransactionalTestExecutionListener를 통해 실행되거나 AbstractTransactionalUnit4SpringContextTests를 서브 클래 싱하는 것이지만, @Rollback 주석없이 테스트를 실행하거나 이벤트가 실행되지 않는 것처럼 보입니다.) @Rollback 테스트를 수행하면서 @TransactionalEvents를 테스트 하시겠습니까?

해결법

  1. ==============================

    1.Stéphane Nicoll은 맞습니다. @TransactionalEventListener의 TransactionPhase가 AFTER_COMMIT로 설정된 경우 자동 롤백 의미론을 사용하여 트랜잭션 테스트를 수행하는 것은 이벤트가 절대로 실행되지 않으므로 의미가 없습니다.

    Stéphane Nicoll은 맞습니다. @TransactionalEventListener의 TransactionPhase가 AFTER_COMMIT로 설정된 경우 자동 롤백 의미론을 사용하여 트랜잭션 테스트를 수행하는 것은 이벤트가 절대로 실행되지 않으므로 의미가 없습니다.

    즉, 트랜잭션이 커밋되지 않은 경우 트랜잭션이 커밋 된 후 이벤트가 시작되는 방법이 없습니다.

    따라서 이벤트를 실행하려면 트랜잭션을 커밋해야합니다 (예 : 테스트 메소드에 @Commit 주석을 달아서). 커밋 후에 정리하려면 격리 모드에서 @Sql을 사용하여 트랜잭션이 커밋 된 후 정리 스크립트를 실행할 수 있어야합니다. 예를 들어, 다음과 같은 (테스트되지 않은 코드)가 작동 할 수 있습니다.

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

    문안 인사,

    Sam (Spring TestContext Framework 작성자)

  2. ==============================

    2.Sam Brannen의 해결책은 adam의 의견과 관련하여 거의 작동합니다.

    Sam Brannen의 해결책은 adam의 의견과 관련하여 거의 작동합니다.

    사실, @TransactionalEventListener로 주석 된 메소드는 테스트 메소드 트랜잭션이 커밋 된 후에 호출됩니다. 이는 이벤트를 발생시키는 호출 메소드가 실제 트랜잭션이 아닌 논리적 트랜잭션 내에서 실행되기 때문입니다.

    대신, 호출 메소드가 새로운 물리적 트랜잭션 내에서 실행될 때, @TransactionalEventListener로 주석 처리 된 메소드는 적시에, 즉 테스트 메소드 트랜잭션이 커밋되기 전에 호출됩니다.

    또한 우리는 실제로 이러한 트랜잭션에 관심이 없기 때문에 테스트 메소드에 @Commit이 필요하지 않습니다. 그러나 Sam Brannen이 설명하는 @Sql (...) 문이 호출 된 메서드의 커밋 된 변경 내용을 취소하려면 필요합니다.

    아래의 작은 예를 참조하십시오.

    먼저 트랜잭션이 커밋 될 때 호출되는 리스너 (@TransactionalEventListener의 기본 비헤이비어)

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

    그런 다음 위의 클래스에서 청취 한 이벤트를 게시하는 애플리케이션 서비스. 메소드가 호출 될 때마다 트랜잭션이 새로운 물리적 인 트랜잭션이되도록 구성되어 있습니다 (자세한 내용은 Spring Framework 문서를 참조하십시오) :

    @Service
    @Transactional(propagation = Propagation.REQUIRES_NEW)
    public class MyApplicationService {
    
        public void doSomething() {
            // ...
            // publishes an instance of MyEvent
            // ...
        }
    }
    

    마지막으로 Sam Brannen이 제안한 테스트 방법으로 @Commitannotation은 필요하지 않습니다.

    @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
        // ...
    }
    

    이렇게하면 매력처럼 작동합니다 :-)

  3. from https://stackoverflow.com/questions/36536466/testing-transactionalevents-and-rollback by cc-by-sa and MIT license