2024-06-17 오늘의 TIL - 테스트 코드(1)

이재성·2024년 6월 18일
post-thumbnail

테스트 코드

주 목적은 오류를 줄이고 버그에 빠르게 대처하기위해서이다.

  • JUnit
  • Mockito 등 사용

스프링에서는 단위 테스트와 통합테스트가 있다.

작성법

Given/When/Then 패턴

Given : 어떠한 데이터가 주어질 때.
When : 어떠한 기능을 실행하면.
Then : 어떠한 결과를 기대한다.

  @Test
  @DisplayName("TestName")
  void test() {
      // Given

      // When

      // Then
  }

단위 테스트

단위테스트는 하나의 기능 또는 메서드를 기준으로 독립적으로 진행되는 가장 작은 단위의 테스트

  • 일반적인 테스트 코드 작성

  • 테스트하고자 하는 부분만 독립적으로 테스트를 진행
    -> 빠른 작성과 문제 여부를 확인

한계

독립적인 테스트 즉, 다른 객체와 데이터를 주고 받는 경우에 문제가 발생
기능과 연관된 모듈에서 가짜 데이터, 정해진 반환값을 넣어주어야함

통합 테스트

다른 객체들과 데이터를 주고받으며 기능이 수행 될때, 연관된 객체들과 올바르게 동작하는지 검증
단위 테스트와는 달리 주로 연관기능 동작 확인하며 실제 운영 환경과 유사한 조건에서 테스트를 수행한다.

한계?

전반적인 동작과 상호작용을 검증하는 것이기에 엄청나게 긴 시간이 소요되며 에러가 났을 때 어디서 나는 에러인지 감을 잡기가 힘들다.

DTO 테스트 해보기

public class DtoTest implements CommonTest {
    private Validator validator = null;
    @BeforeEach
    public void setUp() {
         validator = Validation.buildDefaultValidatorFactory().getValidator();
    }

    @Nested
    @DisplayName("보드 dto 테스트")
    class boardRequestTest{
        @Test
        @DisplayName("요청 dto 생성 성공")
        void boardRequestTest_ok(){
            //given
            BoardRequestDto boardRequestDto = new BoardRequestDto();
            boardRequestDto.setTitle(BOARD_TITLE);
            boardRequestDto.setContent(BOARD_CONTENT);

            //when
            Set<ConstraintViolation<BoardRequestDto>> violations = validator.validate(boardRequestDto);

            //then
            assertThat(violations).isEmpty();
        }
        @Test
        @DisplayName("Dto 제목 비어있을경우")
        void boardRequestTest_badTitle(){
            //given
            BoardRequestDto boardRequestDto = new BoardRequestDto();
            boardRequestDto.setTitle(null);
            boardRequestDto.setContent(BOARD_CONTENT);

            //when
            Set<ConstraintViolation<BoardRequestDto>> violations = validator.validate(boardRequestDto);

            //then
            assertThat(violations).hasSize(1);
            assertThat(violations).extracting("message").contains("제목을 입력해주세요.");
        }
        @Test
        @DisplayName("Dto 내용 비어있을경우")
        void boardRequestTest_badContent(){
            //given
            BoardRequestDto boardRequestDto = new BoardRequestDto();
            boardRequestDto.setTitle(BOARD_TITLE);
            boardRequestDto.setContent(null);

            //when
            Set<ConstraintViolation<BoardRequestDto>> violations = validator.validate(boardRequestDto);

            //then
            assertThat(violations).hasSize(1);
            assertThat(violations).extracting("message").contains("내용을 입력해주세요.");
        }
    }
    @Nested
    @DisplayName("SignRequestDto Test")
    class signRequestTest{

        @Test
        @DisplayName("요청 성공")
        void signRequestTest_ok(){
            //given
            SignupRequestDto signupRequestDto = new SignupRequestDto();
            signupRequestDto.setUsername(USERNAME);
            signupRequestDto.setPassword(PASSWORD);
            signupRequestDto.setNickname(NICKNAME);
            signupRequestDto.setEmail(EMAIL);
            signupRequestDto.setInfo(INFO);

            //when
            Set<ConstraintViolation<SignupRequestDto>> violations = validator.validate(signupRequestDto);

            //then
            assertThat(violations).isEmpty();
        }
        @Test
        @DisplayName("요청 실패(username)")
        void signRequestTest_badUsername(){
            //given
            SignupRequestDto signupRequestDto = new SignupRequestDto();
            signupRequestDto.setUsername("INVALIDNAME");
            signupRequestDto.setPassword(PASSWORD);
            signupRequestDto.setNickname(NICKNAME);
            signupRequestDto.setEmail(EMAIL);
            signupRequestDto.setInfo(INFO);

            //when
            Set<ConstraintViolation<SignupRequestDto>> violations = validator.validate(signupRequestDto);

            //then
            assertThat(violations).hasSize(1);
            assertThat(violations).extracting("message").contains("사용자 ID는 최소 10글자 이상, 최대 20글자 이하여야 합니다.");
        }
        @Test
        @DisplayName("요청 실패(password)")
        void signRequestTest_badPassword(){
            //given
            SignupRequestDto signupRequestDto = new SignupRequestDto();
            signupRequestDto.setUsername(USERNAME);
            signupRequestDto.setPassword("sdfsdfsdf12");
            signupRequestDto.setNickname(NICKNAME);
            signupRequestDto.setEmail(EMAIL);
            signupRequestDto.setInfo(INFO);

            //when
            Set<ConstraintViolation<SignupRequestDto>> violations = validator.validate(signupRequestDto);

            //then
            assertThat(violations).hasSize(1);
            assertThat(violations).extracting("message").contains("대소문자 포함 영문 + 숫자 + 특수문자를 최소 1글자씩 포함합니다. \n비밀번호는 최소 10글자 이상이어야 합니다.");
        }
        @Test
        @DisplayName("요청 실패(nickname)")
        void signRequestTest_badNickname(){
            //given
            SignupRequestDto signupRequestDto = new SignupRequestDto();
            signupRequestDto.setUsername(USERNAME);
            signupRequestDto.setPassword(PASSWORD);
            signupRequestDto.setNickname(null);
            signupRequestDto.setEmail(EMAIL);
            signupRequestDto.setInfo(INFO);

            //when
            Set<ConstraintViolation<SignupRequestDto>> violations = validator.validate(signupRequestDto);

            //then
            assertThat(violations).hasSize(1);
            assertThat(violations).extracting("message").contains("Required Nickname");
        }


    }
    @Nested
    @DisplayName("Like Dto Test")
    class likeDtoTest{
        @Test
        @DisplayName("Dto 요청 성공")
        void likeDtoTest_ok(){
            //given
            LikeDto likeDto = new LikeDto();
            likeDto.setContentId(CONTENT_ID);
            likeDto.setContentType(LIKE_TYPE_ENUM.toString());

            //when
            Set<ConstraintViolation<LikeDto>> violations = validator.validate(likeDto);

            //then
            assertThat(violations).isEmpty();
        }
        @Test
        @DisplayName("Dto 요청 실패(id null)")
        void likeDtoTest_badId(){
            //given
            LikeDto likeDto = new LikeDto();
            likeDto.setContentId(null);
            likeDto.setContentType(LIKE_TYPE_ENUM.toString());

            //when
            Set<ConstraintViolation<LikeDto>> violations = validator.validate(likeDto);

            //then
            assertThat(violations).hasSize(1);
            assertThat(violations).extracting("message")
                    .contains("Content ID는 필수입니다.");
        }
        @Test
        @DisplayName("Dto 요청 실패(type)")
        void likeDtoTest_badType(){
            //given
            LikeDto likeDto = new LikeDto();
            likeDto.setContentId(CONTENT_ID);
            likeDto.setContentType("45623");

            //when
            Set<ConstraintViolation<LikeDto>> violations = validator.validate(likeDto);

            //then
            assertThat(violations).hasSize(1);
            assertThat(violations).extracting("message")
                    .contains("영어만 입력 가능합니다.");
        }
    }

}

Entity Test 해보기

public class EntityTest implements CommonTest {
    @Nested
    @DisplayName("User Entity 테스트")
    class UserEntity {
        User user;
        @BeforeEach
        void setUp() {
            user = CommonTest.user;
        }
        @Test
        @DisplayName("softDelete Test")
        void softDeleteTest() {
            //no given
            //when
            user.softDelete();
            //then
            assertEquals(user.getStatus(),DELETED);
            assertNotNull(user.getDeletedAt());
        }
        @Test
        @DisplayName("updateToken Test")
        void updateTokenTest() {
            //given
            String refreshToken = "test1234";
            //when
            user.updateToken(refreshToken);
            //then
            assertEquals(refreshToken, user.getRefreshToken());
        }
        @Test
        @DisplayName("setExpired Test")
        void setExpiredTest() {
            //given
            boolean expired = true;
            //when
            user.setExpired(expired);
            //then
            assertEquals(expired, user.isExpired());
        }
    }
    @Nested
    @DisplayName("Board Entity 테스트")
    class BoardEntity{
        Board board;
        @BeforeEach
        void setUp() {
            board = new Board();
        }
        @Test
        @DisplayName("hitsUp Test")
        void hitsUpTest() {
            //given
            board.setHits(0L);
            //when
            board.hitsUp();
            //then
            assertEquals(1, board.getHits());
        }
        @Test
        @DisplayName("update Test")
        void updateTest() {
            //given
            BoardRequestDto boardRequestDto = new BoardRequestDto();
            boardRequestDto.setTitle("게시물제목");
            boardRequestDto.setContent("게시물내용");
            //when
            board.update(boardRequestDto);
            //then
            assertEquals("게시물제목", board.getTitle());
            assertEquals("게시물내용", board.getContent());
            assertNotNull(board.getModifiedAt());
        }
    }
    @Nested
    @DisplayName("Comment Test")
    class CommentEntity{
        Comment comment;
        @BeforeEach
        void setUp() {
            comment = new Comment();
        }
        @Test
        @DisplayName("update Test")
        void updateTest() {
            //given
            CommentRequestDto commentRequestDto = new CommentRequestDto();
            commentRequestDto.setContent("댓글내용");
            //when
            comment.update(commentRequestDto);
            //then
            assertEquals("댓글내용", comment.getContent());
        }
        @Test
        @DisplayName("delete Test")
        void deleteTest() {
            //no given
            //when
            comment.delete();
            //then
            assertNotNull(comment.getDeletedAt());
        }
        @Test
        @DisplayName("isCommentAuthor Test")
        void isCommentAuthorTest() {
            //given
            User user = new User();
            Long userId = 1L;
            //when
            boolean answer =  comment.isCommentAuthor(userId);
            //then
            assertTrue(true, String.valueOf(answer));
        }
    }
}

회고

뭔가 검증하는게 더 머리가 아픈 일인거 같다.
엔티티와 DTO 테스트는 그래도 필드 주입하고 예외 처리가 잘 되는지만
체크하면되서 에러가 거의 발생 하지 않았는데
컨트롤러 테스트를 진행하자마자 엄청난 에러 메세지를 보고 있다.
왜 필터관련 에러가 계속 나오는지 알아보아야겠다.

profile
하이요

0개의 댓글