인프런 커뮤니티 질문&답변

정윤수님의 프로필 이미지

작성한 질문수

호돌맨의 요절복통 개발쇼 (SpringBoot, Vue.JS, AWS)

게시글 조회 1 - 단건조회

Testcase 상에서 @Trasactional 사용시

23.03.24 22:22 작성

·

595

3

  • 당연히 구글링 해보셨져? 원하는 결과를 못찾으셨나요? 어떤 검색어를 입력했는지 알려주세

  • 문제가 발생한 코드(프로젝트)를 Github에 올리시고 링크를 알려주세요.

안녕하세요. 호돌맨님 강의 잘 보고 있습니다! Post 관련 테스트를 작성할 때, 저는 @Transactional을 이용해서 DB에 데이터가 반영되지 않도록 시도했습니다.그리고 테스트를 진행하였습니다. 메서드를 각각 테스틀 할 때는 통과했지만, 메서드 모두 동시에 돌릴 때는 테스트 통과에 실패하였습니다. @Transcational, 영속성 컨텍스트로 구글링을 시도했었습니다. @DirtiesContext(classMode = ClassMode.AFTER_EACH_TEST_METHOD)를 사용하면 영속성 컨텍스트를 새로 생성함으로써 테스트가 모두 통과가 되었지만, 매번 영속성 컨텍스트를 새로 생성하는 것은 비효율적이라고 생각했습니다.. 결론적으로 제가 본 바로는 유의미한 결과를 얻을 수 없었습니다.. 아래 코드와 그에 출력되는 결과를 이미지로 첨부해두었습니다. 혹시 어떤 것이 원인인건지 힌트라도 알려주실 수 있을까요?? 구글링 키워드를 알려주셨으면 좋겠습니다..! (해결법은 제가 찾겠습니다!!)

PostService.java



@Service
@RequiredArgsConstructor
@Transactional(readOnly = true)
public class PostService {
    private final PostRepository postRepository;

    @Transactional
    public void save(PostCreateDto postCreate){
//        Post post = new Post(postCreate.getTitle(), postCreate.getContent());
        Post post = Post.builder()
                    .title(postCreate.getTitle())
                    .content(postCreate.getContent())
                    .build();

        postRepository.save(post);
    }

    public Long findPostById(Long postId){
        Post post = postRepository.findById(postId)
                .orElseThrow(() -> new IllegalArgumentException("존재하지 않는 게시물입니다."));
        return post.getId();
    }
}

 

PostServiceTest.java

import com.toktok.core.domain.post.Post;
...

@SpringBootTest
@Transactional.  //똑같이 영속성 컨텍스트를 공유하고 있기 때문에 save가 롤백되어야 하지 않나요??..
class PostServiceTest {

    @Autowired
    private PostService postService;

    @Autowired
    private PostRepository postRepository;

    @Test
    @DisplayName("데이터가 저장 되어야합니다.")
    void save_test(){
        //given
        PostCreateDto postDto = PostCreateDto.builder()
                .title("제목입니다.")
                .content("내용입니다.")
                .build();
        //when
        postService.save(postDto);
        //then
        Post post = postRepository.findAll().get(0);

        assertThat(post.getId()).isEqualTo(1L);
        assertThat(post.getTitle()).isEqualTo(postDto.getTitle());
    }

    @Test
    @DisplayName("데이터는 하나 조회")
    void find_test(){
        //given
        Long postId = 1L;
        PostCreateDto postDto = PostCreateDto.builder()
                .title("글 제목입니다.")
                .content("글 내용입니다.")
                .build();
        postService.save(postDto);

        //when
        Long postById = postService.findPostById(1L);

        //then
        assertThat(postById).isEqualTo(1L);
    }

    @Test
    @DisplayName("존재하지 않는 데이터 확인")
    void not_exist_post(){
        //given
        Long notExistPostId = 2L;

        Post post = Post.builder()
                    .title("글 제목입니다.")
                    .content("글 내용입니다.")
                    .build();

        Post savedPost = postRepository.save(post);

        //when
        postService.findPostById(savedPost.getId());

        //then
        assertThrows(IllegalArgumentException.class, ()-> postService.findPostById(notExistPostId));

    }
}

 



답변 1

1

호돌맨님의 프로필 이미지
호돌맨
지식공유자

2023. 03. 27. 11:15

안녕하세요. 호돌맨입니다.
흥미로운 테스트 방법 공유 감사합니다.

문제해결

@Transactional이 걸려도 테스트 메서드가 수행되면 기본적으로 롤백이 됩니다. 따라서 두 번째 테스트 데이터는 하나 조회 메서드에서 이 전에 저장된 ID 값인 1L의 Post를 찾을 수 없게됩니다.

image

해당 내용은 [스프링 공식 문서](https://docs.spring.io/spring-framework/docs/current/reference/html/testing.html#testcontext-tx-rollback-and-commit-behavior)에 나와있습니다.

@Transactional이 아닌 @Rollback(false)를 추가하시면 윤수님이 의도한대로 작동할겁니다.

그런데

윤수님의 궁금증으로 테스트 하고 계신지 실제 이런 테스트 방식으로 진행 하실지는 잘 모르겠으나 몇 가지 덧 붙입니다.

이런식의 명시적이지 않은 의존 테스트는 좋은 방식이 아닙니다.

현재는 데이터저장 테스트 한 가지 메서드만 의존하고 있지만 앞으로 다른 테스트가 추가될때 이런 의존성이 높아질 위험이 있습니다. 향후에 윤수님이 아닌 다른 누군가가 나중에 데이터저장 테스트를 수정할때를 생각해보면 그 누구도 데이터조회 테스트를 고려하지 않을 겁니다.
또한 앞으로 추가될 테스트가 이 전에 저장 되어버린 데이터(Post=1)로 인하여 의도치않게 테스트 실패 또는 성공이 될 수 있습니다.

또한 데이터저장 테스트 > 데이터조회 테스트 와 같이 테스트 순서를 보장할 수 없습니다. 현재는 저장 후 조회하는 메서드가 실행되지만 항상 보장될 수 있는건 아닙니다. 앞으로 테스트 메서드가 추가됨에 따라 언제든지 달라질 수 있습니다.

각 테스트 수행 메서드는 명확하게 데이터가 정리된 상태에서 환경구성, 수행, 검증하는 것을 추천합니다.

감사합니다.

정윤수님의 프로필 이미지
정윤수
질문자

2023. 03. 28. 10:31

호돌맨님 감사합니다! 많은 것을 알려주시고, 구글링을 하는 법까지 간접적으로 알려주셔서 너무 감사합니다!!! 호돌맨님 최고십니다:)