@Transaction

jihan kong·2022년 9월 6일
0

JUnit5

목록 보기
10/25
post-thumbnail

본 시리즈는 메타 코딩님의 Junit 강의를 학습한 내용을 바탕으로 정리하였습니다.

바로 전 포스팅에서 책을 수정하는 작업을 위한 테스트 코드를 작성했었다.

그런데 한 가지 의문점이 생겼다. 테스트를 실행하자 우리가 예상했던 결과와는 다른 결과가 나타났는데 분명 메서드 위에 @Sql("classpath:db/tableIni.sql") 쿼리를 작성했고 이를 통해 테이블을 모두 날렸음에도 테스트 진행시에 @BeforeEach 에서 삽입된 값이 삭제되지 않고 출력된 것이다.

이는 JUnit의 @Transaction 메서드의 특징을 잘 파악하고 있어야 이해가 가능하다. 먼저 JUnit의 특징에 대해서 간략하게 알아보자.

JUnit이란?

  • 테스트 도구
  • 정확히는 라이브러리
  • 기본 동작 흐름
    : 메서드 실행 -> 종료 -> RollBack

JUnit의 Transaction은 항상 다음의 실행 주기를 가진다.

  • 메서드 1 실행
    -> 트랜잭션 시작
  • 메서드 2 실행
  • 마지막 메서드 3 실행
    -> 트랜잭션 종료
    -> RollBack

이처럼 모든 로직이 끝나고 트랜잭션이 종료되면 자동으로 RollBack 작업을 실행한다.


다음의 코드를 살펴보자.

@SpringBootTest
@AutoConfigureMockMvc
@Transactional
class SaveControllerTest {
 
    @Test
    @DisplayName("TEST 데이터 저장")
    @Rollback(false) // rollback 되지 않도록 설정
    void saveTest() throws Exception {
        /* param set */
        TestDto testDto = new TestDto();
        testDto.setName("test");
        
        MvcResult result = mockMvc.perform(post("/test/saveTest")
                        .contentType(MediaType.APPLICATION_JSON)
                        .content(toJson(rmVenParamDto)))
                .andExpect(status().isOk())
                .andReturn();
                
        ...
    }
}
// 출처 : 서해바다님의 블로그 (https://devfunny.tistory.com/721)

위 코드의 경우, Test 데이터를 저장하고 Rollback 이 되지 않도록 옵션을 통해 false로 지정한 것이지만 원래 Rollback 의 기본값은 True이다.

이처럼 메서드가 종료되기만을 기다렸다가(?) 종료되면 Transaction은 가차없이 Rollback 을 실행한다.

그런데, RollBack이 무엇인가요❓
-> 코딩 병원님의 블로그 참조 https://itprogramming119.tistory.com/entry/Oracle-ROLLBACK%EC%9D%98-%EA%B0%9C%EB%85%90%EA%B3%BC-%EA%B3%BC%EC%A0%95

물론 실제 서버에서는 변경사항이 있을 때 기본적으로 Commit이 진행될 것이다. RollBack이 일어나는 경우는 RuntimeException 이 발생했을 때에만 해당된다.


그렇다면 왜 BeforeEach의 내용이 저장되어 있나?

우리가 예상한 @SQL 의 동작 시점은 다음과 같다.

(트랜잭션 시작)
(1) beforeEach 메서드 실행
(2) sql 실행
(3) update 메서드 실행
(트랜잭션 종료)

언뜻 보면 맞는 것 같다. beforeEach는 테스트가 실행되기 전에 실행이 되는 메서드이기 때문에 가장 먼저 실행되고, update 메서드가 실행되기 전에 sql 어노테이션이 있기 때문이다.

그러나 사실 우리는 @SQL 어노테이션의 동작 시점에 대해 잘못 이해하고 있다.

@SQL의 동작 시점

@SQL 은 메서드가 실행되기 직전에 실행이 된다.

우리가 @BeforeEach 로 구현한 데이터 준비() 메서드도 엄연한 메서드이다. 따라서 트랜잭션이 시작하고 BeforeEach 메서드가 실행되기도 전에 실행이 되는 것이다.

따라서 흐름을 다시 수정하면 이렇게 된다.

(트랜잭션 시작)
(1) sql 실행
(2) beforeEach 메서드 실행
(3) update 메서드 실행
(트랜잭션 종료)

트랜잭션이 시작되고 모든 메서드의 실행 이전에 @SQL로 테이블의 내용을 다 날리는 것이 우선했고, beforeEach는 그 다음에 실행되기 때문에 update 메서드에서 bookRepository의 내용을 출력했을 때 그 내용이 출력이 되는 것이다.

profile
학습하며 도전하는 것을 즐기는 개발자

0개의 댓글