728x90

이전글

 

[04] Post Test 코드 작성 - 1 (Controller Test)

이전글 [04] User Test 코드 작성 이전글 [03] 게시된 포스트 삭제 이전글 [03] 게시된 포스트 수정 이전글 [03] 게시된 모든 포스트 목록 보기 이전글 [03] 포스트 등록 만들기 체크 사항 로그인이 되어

chordplaylist.tistory.com

목표

  • 1. controller / 2. service로 나눠서 테스트를 진행해야 함.
  • 1. 성공, 2. 실패 테스트 케이스를 모두 통과하는 실제 코드 작성.
  • Exception 처리는 enum Error코드에 작성 후 호출 해서 사용
    • 실패의 경우 enum값의 errorCode로 처리하기
  • when(어떤 상황일 때)를 각각 설계해 보고, Test case에 따라 예상되는 결괏값을 작성해 주기
  • Controller, Service 두 클래스의 테스트 코드 작성하기

체크사항

포스트 단건 조회(상세 보기)

service

  • 조회 성공

포스트 등록

service

  • 등록 실패 : 유저가 존재하지 않을 때
  • 등록 성공

포스트 수정

service

  • 수정 실패 : 포스트 존재하지 않음
  • 수정 실패 : 작성자!=유저
  • 수정 실패 : 유저 존재하지 않음

포스트 삭제

service

  • 삭제 실패 : 유저 존재하지 않음
  • 삭제 실패 : 포스트 존재하지 않음

Post Service Test

Basic

class PostServiceTest {
    private PostService postService;

    private PostRepository postRepository = mock(PostRepository.class);
    private UserRepository userRepository = mock(UserRepository.class);


    @BeforeEach
    void setUp() {
        postService = new PostService(postRepository, userRepository);
    }
}
  1. 사용할 Repository를 mock을 사용하여 초기화시켜 줍니다.
  2. @BeforeEach를 사용해서 PostService에서 사용할 Repository를 초기화시킵니다.

포스트 단건 조회(상세 보기)

조회 성공

class PostServiceTest {
    ...
    /* 포스트 상세 */
    @Test
    @DisplayName("조회 성공")
    void success_get_post() {
        Post fixture = PostFixture.get();

        when(postRepository.findById(any())).thenReturn(Optional.of(fixture));
        PostReadResponse response = postService.getPost(fixture.getId());
        assertEquals(fixture.getUser().getUserName(), response.getUserName());
    }
}
  1. postRepository의 findById를 사용하게 되면 Post 타입의 fixture를 반환하도록 설정했다.
  2. PostReadResponse에 getPost메서드를 사용해서 fixture의 postId를 사용하여 데이터를 저장받았다.
  3. fixture의 값과 response의 값이 동일한지 비교하였다.

포스트 등록

등록 성공

class PostServiceTest {
    ...
    /* 포스트 등록 */
    @Test
    @DisplayName("등록 성공")
    void success_post() {
        User user = UserFixture.get("chordpli", "1234");
        PostRequest request = new PostRequest("title", "body");

        Post mockPost = mock(Post.class);

        when(userRepository.findByUserName(any()))
                .thenReturn(Optional.of(user));
        when(postRepository.save(any()))
                .thenReturn(mockPost);

        Assertions.assertDoesNotThrow(() -> postService.post(request, user.getUserName()));
    }
  1. userId와 password를 넣어서 저장된 User값을 불러옵니다.
  2. Post를 작성하기 위한 request를 생성합니다.
  3. postRepository의 save메서드를 사용했을 때 반환받을 mock post를 생성합니다.
  4. userRepository의 findByUserName을 사용했을 때 user를 반환합니다.
  5. postRepository를 save 했을 때 mock으로 된 post를 반환합니다.
  6. postSerivce의 post를 진행했을 때 예외가 던져지지 않는다면 통과합니다.

등록 실패 - 유저가 존재하지 않을 때

class PostServiceTest {
    ...

    /* 포스트 등록 */
    @Test
    @DisplayName("등록 실패_존재하지 않은 유저")
    void fail_post_not_exist_user() {
        User user = UserFixture.get("chordpli", "1234");
        PostRequest request = new PostRequest("title", "body");
        when(userRepository.findByUserName(user.getUserName())).thenReturn(Optional.empty());
        SNSAppException exception
                = Assertions.assertThrows(SNSAppException.class,
                () -> postService.post(request, user.getUserName()));
        Assertions.assertEquals(ErrorCode.USERNAME_NOT_FOUND, exception.getErrorCode());
    }
}
  1. 저장되어있는 User 정보를 가지고 옵니다.
  2. Post를 작성하기 위한 request를 생성합니다.
  3. userRepository의 findByUserName을 실행했을 때 empty를 반환받습니다.
  4. assertThrows를 사용해서 post 메서드를 사용했을 때 SNSAppExcpeiont을 발생시킵니다.
  5. excpeiont이 발생한 error코드와 USERNAME_NOT_FOUND가 동일한지 확인합니다.

포스트 수정

수정 성공

class PostServiceTest {
    ...
    /* 포스트 수정 */
    @Test
    @DisplayName("수정 성공")
    void success_modify_post(){
        Post fixture = PostFixture.get();
        User user = UserFixture.get("chordpli", "1234");

        when(postRepository.findById(any())).thenReturn(Optional.of(fixture));
        when(userRepository.findByUserName(any())).thenReturn(Optional.of(user));

        PostModifyRequest request = new PostModifyRequest("수정 제목", "수정 내용");

        fixture.setTitle(request.getTitle());
        fixture.setTitle(request.getBody());

        when(postRepository.save(any()))
                .thenReturn(fixture);

        Assertions.assertDoesNotThrow(() -> postService.modifyPost(fixture.getId(), request, user.getUserName()));
        assertEquals(fixture.getTitle(), request.getTitle());
    }
}
  1. 저장된 Post와 User의 정보를 받아옵니다.
  2. postRepository의 findById를 사용하면 fixture를 반환받습니다.
  3. userRepository의 findByUserName을 사용하면 user를 반환받습니다.
  4. 수정할 내용을 받을 request를 생성합니다.
  5. fixture를 수정하고, postRespository의 save를 사용했을 때 수정된 fixture를 반환받습니다.
  6. postService.modify를 사용했을 때 예외가 발생하지 않으면 통과합니다.
  7. fixture의 title과 수정 요청된 title이 동일한지 확인합니다.

수정 실패 - 포스트가 존재하지 않을 때

class PostServiceTest {
    ...
    /* 포스트 수정 */
    @Test
    @DisplayName("수정 실패_포스트가 존재하지 않음")
    void fail_modify_post_not_exist_post() {
        Post fixture = PostFixture.get();
        when(userRepository.findByUserName(any())).thenReturn(Optional.of(mock(User.class)));
        when(postRepository.save(any())).thenReturn(Optional.empty());
        SNSAppException exception
                = Assertions.assertThrows(SNSAppException.class,
                () -> postService.modifyPost(fixture.getId(), new PostModifyRequest(fixture.getTitle(), fixture.getBody()), fixture.getUser().getUserName()));
        Assertions.assertEquals(ErrorCode.POST_NOT_FOUND, exception.getErrorCode());
    }
}
  1. 저장된 Post의 정보를 받아옵니다.
  2. userRepository의 findByUserName을 사용하면 mockUser를 반환합니다.
  3. postRepository의 save를 사용하면 empty를 반환합니다.
  4. post를 저장했을 때 해당 게시물이 존재하지 않으므로 예외를 발생시킵니다.
  5. exception의 에러코드가 POST_NOT_FOUND인지 확인합니다.

수정 실패 - 포스트의 작성자와 수정 요청을 보내는 유저가 다를 때

    ...
    /* 포스트 수정 */
    @Test
    @DisplayName("수정 실패_작성자와 수정을 요청하는 유저가 다름")
    void fail_modify_post_different_Requester_and_author() {
        Post fixture = PostFixture.get();
        User user = User.builder()
                .id(2)
                .userName("unknown")
                .password("1111")
                .userRole(UserRole.USER)
                .build();

        when(postRepository.findById(any())).thenReturn(Optional.of(new Post(fixture.getId(), fixture.getBody(), fixture.getTitle(), fixture.getUser())));
        when(userRepository.findByUserName(any())).thenReturn(Optional.of(new User(user.getId(), user.getPassword(), user.getUserRole(), user.getUserName())));
        SNSAppException exception
                = Assertions.assertThrows(SNSAppException.class,
                () -> postService.modifyPost(fixture.getId(), new PostModifyRequest(fixture.getTitle(), fixture.getBody()), fixture.getUser().getUserName()));
        Assertions.assertEquals(ErrorCode.INVALID_PERMISSION, exception.getErrorCode());
    }
}
  1. Post와 Post를 작성한 사람과 다른 새로운 User를 생성합니다.
  2. postRepository의 findById를 사용했을 때 Post 정보를 반환합니다.
  3. userRepository의 findByUserName을 사용했을때 User의 정보를 반환합니다.
  4. post의 user와 findByUserName으로 반환받은 User는 서로 다르기 때문에 예외를 발생시킵니다.
  5. exception의 에러코드가 INVALID_PERMISSION인지 확인합니다.

수정 실패 - 유저가 존재하지 않을 때

    ...
    /* 포스트 수정 */
    @Test
    @DisplayName("수정 실패_유저가 존재하지 않음")
    void fail_modify_post_not_exist_user() {
        when(userRepository.findByUserName(any())).thenReturn(Optional.empty());

        SNSAppException exception
                = Assertions.assertThrows(SNSAppException.class,
                () -> postService.modifyPost(fixture.getId(), new PostModifyRequest(fixture.getTitle(), fixture.getBody()), fixture.getUser().getUserName()));
        Assertions.assertEquals(ErrorCode.USERNAME_NOT_FOUND, exception.getErrorCode());
    }
}
  1. userRepository의 findByUserName을 사용했을 때 empty를 반환받습니다.
  2. 수정을 요청하려는 유저가 존재하지 않으므로 예외를 발생시킵니다.
  3. exception의 에러코드가 USERNAME_NOT_FOUND인지 확인합니다.

포스트 삭제

삭제 성공

class PostServiceTest {
    ...

    /* 포스트 삭제 */
    @Test
    @DisplayName("삭제 성공")
    void success_modify_delete(){
        Post fixture = PostFixture.get();
        User user = UserFixture.get("chordpli", "1234");

        when(postRepository.findById(1)).thenReturn(Optional.of(fixture));
        when(userRepository.findByUserName("chordpli")).thenReturn(Optional.of(user));

        assertEquals(fixture.getUser().getUserName(), user.getUserName());
        Assertions.assertDoesNotThrow(() -> postService.deletePost(fixture.getId(), user.getUserName()));
    }
}
  1. 저장된 Post와 User의 값을 불러옵니다.
  2. postRepository의 findById를 했을 때 fixture의 값을 반환받습니다.
  3. userRepository의 fidByUserName을 했을때 user의 값을 반환받습니다.
  4. fixture의 userName과 user의 userName이 동일한지 확인합니다.
  5. postService의 deletePost가 예외 없이 종료된다면 성공합니다.

삭제 실패 - 유저가 존재하지 않을 때

class PostServiceTest {
    ...
    /* 포스트 삭제 */
    @Test
    @DisplayName("삭제 실패_유저가 존재하지 않음")
    void fail_delete_post_not_exist_user() {
        Post fixture = PostFixture.get();

        when(userRepository.findByUserName(any())).thenReturn(Optional.empty());

        SNSAppException exception
                = Assertions.assertThrows(SNSAppException.class,
                () -> postService.deletePost(fixture.getId(), fixture.getUser().getUserName()));
        Assertions.assertEquals(ErrorCode.USERNAME_NOT_FOUND, exception.getErrorCode());
    }
}
  1. 저장된 post의 값을 불러옵니다.
  2. userRepository의 findByUserName을 했을 때 empty를 반환받습니다.
  3. user가 empty임으로 예외를 발생시킵니다.
  4. exception의 error코드가 USERNAME_NOT_FOUND인지 확인합니다.

삭제 실패 - 포스트가 존재하지 않을 때

class PostServiceTest {
    ...
    /* 포스트 삭제 */
    @Test
    @DisplayName("삭제 실패_포스트 존재하지 않음")
    void fail_delete_post_not_exist_post() {
        Post fixture = PostFixture.get();

        when(userRepository.findByUserName(any())).thenReturn(Optional.of(UserFixture.get("chordpli", "1234")));
        when(postRepository.findById(fixture.getId())).thenReturn(Optional.empty());
        SNSAppException exception
                = Assertions.assertThrows(SNSAppException.class,
                () -> postService.deletePost(fixture.getId(), fixture.getUser().getUserName()));

        Assertions.assertEquals(ErrorCode.POST_NOT_FOUND, exception.getErrorCode());
    }
}
  1. 저장된 Post의 값을 불러옵니다.
  2. userRepository의 fidByUserName을 했을때 user의 값을 반환받습니다.
  3. postRepository의 findById를 했을때 empty를 반환합니다.
  4. fixture의 userName과 user의 userName이 동일한지 확인합니다.
  5. postService의 deletePost가 예외 없이 종료된다면 성공합니다.

궁금증

1. any()를 넣으나, fixture.getUser.getUserName()등 임의의 값을 넣으나 이상 없이 테스트 코드는 실행되는데 두 차이점은 무엇일까.

반응형

'프로젝트 > Archive' 카테고리의 다른 글

[05] 리팩토링 - 2  (0) 2022.12.29
[05] 리팩토링 - 1  (0) 2022.12.29
[04] Post Test 코드 작성 - 1 (Controller Test)  (0) 2022.12.27
[04] User Test 코드 작성  (0) 2022.12.26
[JWT] JWT Exception 처리  (0) 2022.12.25
코드플리