요깨비's LAB

[R2dbc] R2dbc Test시 Rollback이 되지 않음. 본문

Java/스프링 Reactive

[R2dbc] R2dbc Test시 Rollback이 되지 않음.

요깨비 2021. 5. 25. 15:59

개인 프로젝트를 진행하던 도중, Test 후 Rollback이 되어야 할 기능이 정상 작동하지 않아 이를 해결한 과정을 적습니다.
해당 방법은 완전한 정답은 아니고, R2dbc를 담당하는 외국 개발자들이 적은 내용들을 참고하여 작성하였습니다.

@SpringBootTest
@Transactional
@DisplayNameGeneration(DisplayNameGenerator.ReplaceUnderscores::class)
class OrderRepositoryTest @Autowired constructor(
    private val orderRepository: OrderRepository
) {
    val log = Slf4JLoggerFactory.getInstance(OrderRepositoryTest::class.java)
    
    @Test
    @DisplayName("[OrderRepository] 주문 생성 테스트")
    fun createOrderTest() {
        val order = Order(
            "create-order-test",
            "product-01",
            "sender1",
            ...
        )
        
        order.setAsNew()
        
        log.info("[OrderRepository] 주문 생성 테스트")
        StepVerifier.create(orderRepository.save(order))
            .expectSubscription()
            .consumeNextWith {
                Assertions.assertEquals("create-order-test", it.orderId)
                log.info("$it")
                log.info("END")
            }
            .verifyComplete()
            
     }
}

주문 생성을 테스트 하던 중 생성 데이터가 롤백이 되지 않았습니다. Stackoverflow를 참조하여 여러 방법들을 적용하였으나,
Rollback이 똑같이 안되거나, Exception이 발생하는 등 적절한 해답이 되지 못했습니다. 그러던 도중 
공식 스프링 Git 사이트에 비슷한 문제를 제기한 ISSUE가 있었습니다. 

공식적인 대답은 

2019년 12월 기준 아직 공식적으로 지원하지 않는 것 같습니다. 또한, 2020년 8월 기준 다른 개발자가 해결 방법이 제시하여
해당 방법으로 문제를 해결하였습니다. 


위 Transaction 코드를 이용하여 해당 객체가 담당하는 책임을 Stepverifier 혹은 Reactive 코드에 적용하여 해당 기능이 끝날 때 Rollback을 수행하도록 하였습니다.

@SpringBootTest
@DisplayNameGeneration(DisplayNameGenerator.ReplaceUnderscores::class)
class OrderRepositoryTest @Autowired constructor(
    private val orderRepository: OrderRepository
) {
    val log = Slf4JLoggerFactory.getInstance(OrderRepositoryTest::class.java)
    
    @Test
    @DisplayName("[OrderRepository] 주문 생성 테스트")
    fun createOrderTest() {
        val order = Order(
            "create-order-test",
            "product-01",
            "sender1",
            ...
        )
        
        order.setAsNew()
        
        log.info("[OrderRepository] 주문 생성 테스트")
        orderRepository.save(order)
            .map(Order::orderId)
            .flatMap(orderRepository::findById)
            .`as`(Transaction::withRollback)
            .`as`(StepVerifier::create)
            .assertNext { order ->
                Assertions.assertEquals(true, order!!.orderId == "create-order-test")
            }
            .verifyComplete()
     }
}

테스트 관련해서 Rollback이 잘 작동하는 것을 확인하였습니다.

해당 방식의 문제점이나 더 나은 개선점이 있으시다면 알려주시면 정말 감사드리겠습니다.

https://github.com/spring-projects/spring-framework/issues/24226

Comments