ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • [내일배움캠프] 3월 2일 목요일 TIL 회고록
    카테고리 없음 2023. 3. 3. 00:48

    오늘 배운 것 : 테스트 코드 작성


    Querydsl은 잠시 미루고 더 급한 테스트 코드를 작성했다.

    원래 Mockito를 사용하여 테스트 코드를 작성하려고 했는데 유저의 이름을 가져오는 부분에서 막혀서.. 

    결국 Mockito를 사용하지 않고 테스트 코드를 작성했다.

     

    스프링부트로 테스트를 할 것이므로 @SpringBootTest 를 사용했다.

    @SpringBootTest
    class CommentServiceImplTest {

    @BeforeEach 를 사용해서 테스트 메서드 실행 이전에 수행되도록 만들었다.

    @BeforeEach
    public void beforeEach() throws IOException {
      Long questionBoardId = 1L;
      Long communityBoardId = 2L;
      // 질문 댓글 작성 요청
      CommentRequest request = new CommentRequest("질문댓글");
      // 잡담 댓글 작성 요청
      CommentRequest request2 = new CommentRequest("잡담댓글");
      // findById를 사용해서 1번 유저 저장
      Optional<User> findUser = userRepository.findById(1L);
    
      // 질문 댓글 작성
      commentService.createQuestionComment(questionBoardId, request, findUser.get());
      // 잡담 댓글 작성
      commentService.createCommunityComment(communityBoardId, request2, findUser.get());
    }

     먼저 질문 댓글 작성 테스트 메서드를 만들었다.

    // 질문 댓글 작성
    @Test
    @DisplayName("질문 댓글 작성")
    void createQuestionComment() {
      // given
      // 질문 댓글 작성 요청
      CommentRequest request = new CommentRequest("질문댓글");
      // 질문 게시글은 1번으로 선언
      Long questionBoardId = 1L;
      // findById를 사용해서 1번 유저 저장
      Optional<User> findUser = userRepository.findById(1L);
    
      // when
      // 질문 댓글 작성 ("질문댓글")
      commentService.createQuestionComment(questionBoardId, request, findUser.get());
      // findById를 사용해서 1번 유저 저장(BeforeEach 메서드에서 만든 댓글)
      Optional<Comment> findComment = commentRepository.findById(1L);
    
      // then
      // request.genContent() = "질문댓글" 이랑 
      // findComment.get().getContent() = "질문댓글" 이랑 같은지 확인
      assertThat(request.getContent()).isEqualTo(findComment.get().getContent());
    }

    실행 결과

    질문 댓글을 수정하는 기능 테스트 메서드를 만들어봤다.

    @Test
    @DisplayName("질문 댓글 수정")
    void updateQuestionComment() {
      // given
      // findById로 1번 유저 저장
      Optional<User> findUser = userRepository.findById(1L);
      // 질문 댓글 작성 요청("질문댓글수정")
      CommentRequest commentRequest = new CommentRequest("질문댓글수정");
      // when
      // 질문 댓글 업데이트 ("질문댓글" 에서 "질문댓글수정" 으로)
      commentService.updateQuestionComment(1L, commentRequest, findUser.get());
      // findById를 사용해서 1번 댓글 저장(위에 기능때문에 댓글 내용이 "질문댓글수정"으로 변함
      Optional<Comment> questionComment = commentRepository.findById(1L);
      // then
      // questionComment.get().getContent() = "질문댓글수정" 이랑
      // commentRequest.getContent() = "질문댓글수정" 이랑 같은지 확인하는 기능
      assertThat(questionComment.get().getContent()).isEqualTo(commentRequest.getContent());
    }

    실행 결과

    질문 삭제 기능 테스트 메서드도 만들었다.

    @Test
    @DisplayName("질문 댓글 삭제")
    void deleteQuestionComment() {
      // given
      // findById를 사용해서 1번 유저 저장
      Optional<User> findUser = userRepository.findById(1L);
      // findById를 사용해서 1번 질문 댓글 저장
      Optional<Comment> findComment = commentRepository.findById(1L);
      // when
      // 1번 댓글을 지우는 기능
      commentService.deleteQuestionComment(1L, findUser.get());
      // then
      // commentRepository.existCommentById를 사용해서 1번 댓글이 있는지 확인한다.
      // 그리고 isFalse()를 사용해서 댓글이 없는지 확인한다.
      assertThat(commentRepository.existsCommentById(1L)).isFalse();
    }

    실헹 결과

    잡담 댓글 작성/수정/삭제도 위에 코드랑 일치해서 패스!

     

    내가 쓴 댓글 조회 기능 테스트 메서드도 만들었는데 이렇게 만드는게 맞는지 애매하다.

    @Test
    @DisplayName("내가 쓴 댓글 조회")
    void getMyComments() {
      // given
      // 페이징 처리 기능이 있는 CommentList 생성자를 불러온다.
      CommentList commentList = new CommentList();
      // findById를 사용해서 1번 유저를 저장
      Optional<User> findUser = userRepository.findById(1L);
      // findById를 사용해서 1번 댓글을 저장
      Optional<Comment> findComment = commentRepository.findById(1L);
      // when
      // getMyComments를 사용해서 내가 쓴 댓글 조회 (페이징 처리)
      commentService.getMyComments(commentList, findUser.get().getId(), findUser.get());
      // then
      // 여기서 생각을 되게 많이했는데.. 이게 맞는지 모르겠다.
      assertThat(commentList.toPageable()).isNotNull();
    }

    마지막 then에 검증을 하는 부분을 어떻게 해야할지 모르겠다.. ㅠㅠ 일단 저렇게 하면 테스트 성공이 나오긴 하는데.. 내일 물어봐야겠다.

     

    아직 문제가 있다.. 테스트를 단건으로 실행하면 다 통과하는데 한꺼번에 실행하면 에러가 난다.

    이렇게..

    보면 볼수록 슬프다

    내일 고쳐봐야겠다..  테스트 코드 작성하는건 너무 재밌는데 저렇게 빨간색이 뜨면 참.. 기분이 묘하다 ㅋㅋㅋ


    테스트 코드를 구현하기 전에 api가 잘 동작하는지 테스트를 하려고 했는데 댓글 작성을 하면

    이런식으로 Postman에서 오류를 뱉어내면서 작성, 수정이 전부 안됐다.

    JSON parse error:
    Cannot construct instance of `com.example.lomboktest.SampleDto` 
    (although at least one Creator exists): 
    cannot deserialize from Object value (no delegate- or property-based Creator);

    Controller단에 RequestParam 문제인 것 같아 이름을 바꿔주어도 똑같이 오류가 발생했다.

    구글링을 해보니 @Bulider 어노테이션 사용으로 인해서 해당 오류가 날 수도 있다고 적혀있었다. 

    생각해보니 테스트 코드를 만들때 Builder 를 사용해서 생성자를 만들려고 했었다. 그래서 requestDto를 보니

    @Builder 어노테이션이 붙어있었다. 

    @Getter
    @Builder
    public class CommentRequest {
    
      private String content;
    
    }

    그래서 Builder 어노테이션을 없애고 생성자를 추가해주는 어노테이션을 추가했다.

    추가한 후 api 테스트를 해보니 이상없이 동작한다.

    @Getter
    @NoArgsConstructor(force = true, access = AccessLevel.PROTECTED)
    @RequiredArgsConstructor
    public class CommentRequest {
    
      private final String content;
    
    }

    롬복의 @builder는 기본생성자를 생성해주지 않기에 이런 상황이 발생했다. 다음부터는 조심해서 써야겠다. 

    여기를 보고 참고했다.

    https://91ms.tistory.com/29

     

    @Builder를 추가했더니 잭슨에서 에러가?

    💣📌@RequestBody 에서 DTO 변환시 기본생성자를 필요로한다.일반적인 경우 기본생성자를 사용한다. (리플렉션 통해 생성되기 때문에 Private 가능)@JsonProperty 를 사용하는 프로퍼티 기반 객체는 필요

    91ms.tistory.com

     

     

Designed by Tistory.