테스트코드 Transactional

Kim Dong Kyun·2023년 4월 15일
0

개요

트랜잭셔널 어노테이션을 사용하면 영속성 컨텍스트가 사용되고, 이 안에서 엔티티의 칼럼이 변경되면 변경 감지(Dirty Checking)이 발생해서 트랜잭션의 commit 시점에 변경 사항이 반영된다.

그런데, 테스트코드에서는 안되는거야. 왤까?


예제

  1. Movie 엔티티의 컬럼 inUse를 사용해서 논리 삭제를 하는 로직
    public void softDeleteMovie(){
        this.inUse = false;
    }
  1. 테스트코드 버전 1
@Test
    void softDeleteDefaultTest(){
        Movie movie = movieRepository.findById(1L).orElseThrow(
                () -> new NoSuchElementException("해당하는 영화가 없습니다")
        );
        movie.softDeleteMovie();
    }
  • Movie객체를 찾아 온 후에 논리 삭제하는 테스트
  • 테스트코드에는 기본적으로 Transacsion이 적용된다.

실제 쿼리

  • 그런데, select 쿼리만 날아간다
  1. 테스트코드 버전 2
@Test
@Transactional
    void softDeleteDefaultTest(){
        Movie movie = movieRepository.findById(1L).orElseThrow(
                () -> new NoSuchElementException("해당하는 영화가 없습니다")
        );
        movie.softDeleteMovie();
    }
  • 위와같이 명시적으로 선언해줬다.
  • 그래도 날아가지 않는다.
  1. 버전 3
@Test
    void softDeleteDefaultTest(){
        Movie movie = movieRepository.findById(1L).orElseThrow(
                () -> new NoSuchElementException("해당하는 영화가 없습니다")
        );
        movie.softDeleteMovie();
        
        movieRepository.save(movie); // 명시적 저장
    }
  • Repository.save()매서드를 통해서 명시적 저장(수정) 하는 로직

  • 정상 작동한다

왜???

테스트코드에서 작성되는 모든 코드들은 Transaction 영향을 받는다.

  • 그러나 이것이 실제로 DB에 저장되지 않고, 모두 Rollback 된다
  • 즉, 실제 커밋이 발생하지 않으므로
  • 커밋 시점에 적용되는 더티체킹을 통한 커밋이 작동하지 않는다.

위 디폴트테스트를 이용한 진짜 테스트

    @Test
    void softDeleteMovie() {
        //given
        Movie movie = movieRepository.findById(1L).orElseThrow(
                () -> new NoSuchElementException("해당하는 영화가 없습니다")
        );
        //when
        movie.softDeleteMovie();
        movieRepository.save(movie);

        //then
        List<MovieResponseDto> movies = movieRepository.getMovies(1L);

        assertEquals(2, movies.get(0).getId());
    }

when에서 명시적으로 업데이트를 발생시키고,

그 후 getMovies의 첫번째 요소가 inUse=false로 제거된 1L번 id를 가진 요소가 아닌

2번 id를 가진 요소임을 확인

0개의 댓글