inflearn logo
강의

강의

N
챌린지

챌린지

멘토링

멘토링

N
클립

클립

로드맵

로드맵

지식공유

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

게시글 조회 1 - 단건조회

Testcase 상에서 @Trasactional 사용시

659

정윤수

작성한 질문수 1

3

안녕하세요. 호돌맨님 강의 잘 보고 있습니다! 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));

    }
}

 



vue.js aws spring-boot jpa spring-security

답변 1

1

호돌맨

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

문제해결

@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)로 인하여 의도치않게 테스트 실패 또는 성공이 될 수 있습니다.

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

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

감사합니다.

0

정윤수

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

Deprecated 관련 사항들

0

105

2

깃헙 collaboator 초대 관련

0

89

1

강의 듣다가 도커 이미지 생성시 각각도 가능하나 그렇게 사용하는데가 많은지 모르겠다라는 말을 듣고 남김니다

0

157

2

logout 후에 login 페이지 이동은 어디서 시켜주는건가요?

0

233

1

다중 데이터를 삭제 할 때

0

271

2

querydsl Q class 이슈

0

417

2

Windows WSL Vue 설정

2

247

1

Dip, @transactional

0

189

1

[vite] http proxy error: /auth/login

0

1047

2

로그인 하고 나서 GET요청으로 메인페이지 요청

0

234

2

GitHub Collaborator 초대 관련

0

258

2

Window에서 Vue.js 설정

0

322

2

(솔루션 수정)'tsyringe' Error: TypeInfo not known for "클래스명"

0

713

2

collaboator로 초대받을 수 있을까요??

0

283

2

SecurityMockContext 로부터 유저 정보를 가져오기

0

262

1

given 부분이 길어질 때 어떻게 처리하면 좋을까요?

0

318

1

섹션9 프론트의 코드를 보고싶습니다,,,

0

423

1

Spring Security - defaultSuccessUrl 질문

0

627

1

강의 화면이 나오지 않습니다. 음성과 자막만 나와요

0

302

1

JPAQueryFactory(em)의 객체 생성자 오류에 대해서 질문이 있습니다ㅜㅜ

0

690

2

ExceptionHandler가 AccessDeniedHandler(Http403Handler)를 먹어버리는 현상

0

1182

2

섹션10 언제 나오나요?

0

485

1

CommentService에서 Repository를 호출하지 않는데도

0

345

1

Editor....를 활용한 패턴에 질문있습니다.

0

496

1