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

전병준님의 프로필 이미지
전병준

작성한 질문수

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

게시글 수정

Controller Test 시 Repository 사용 관련 질문입니다.

작성

·

892

1

안녕하세요 호돌맨님 !! 강의 하면서 항상 궁금했던 점인데, 저는 Controller Test 를 End-To-End Test 용도로 자주 활용하고 있는데요, 이러면 Repository Method 를 Controller Test 에서 직접적으로 사용하는 것보다 Service 단 로직을 거쳐 Repository 의 Method 가 호출되도록 하는게 맞는걸까요 ? 호돌맨님은 항상 Controller Test 로직 짜실 때 Repository 의 save() 와 같은 메서드를 한번에 호출해서 사용하는 걸보고 질문 드립니다 !

답변 2

0

전병준님의 프로필 이미지
전병준
질문자

삭제된 글입니다

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

repository.save하는 부분은 조회할 데이터를 준비하는 부분이고요

실질적으로 테스트 대상이 되는 부분은 expected부터 나오는 mockMvc호출이겠죠. 그러면 실제로 controller, 서비스, reppsitory 레이어를 거치면서 비즈니스 로직에 맞게 코드가 실행 될테니깐요.

이 전에 말씀드린대로 repository를 통해 데이터를 준비하는 이유는 비즈니스 로직에 최대한 의존적이지 않게 하려는 거고요.

0

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

안녕하세요. 호돌맨입니다.

질문을 남겨주셔서 감사합니다.

개인적으로 given과정에서는 Repository에 데이터를 직접 저장하는 걸 선호합니다.

또한 when에서 데이터를 검증하는 부분도 별다른 로직이 섞여있지 않은 메서드를 통해 조회해오는 걸 선호합니다.

예를들어

  • 나쁜 예

assertEquals(1, entity.calculateMybusinessCount())

  • 좋은 예

var filteredCount = entity.getMyBusinesses().stream().filter(...).collect(toList));

assertEquals(1, filteredCount);

이런 방법에 용어가 있는지는 모르겠는데.. 저는 Raw하게 or 네이티브하게 테스트데이터를 준비, 검증한다고 표현합니다.

아무튼 그렇게 하는 이유는

  1. 서비스등을 통해 테스트 데이터를 준비시키면 서비스 로직에 따라 테스트코드에 의존성이 생겨버립니다. 그러면 서비스에서 로직이 변경되면 테스트 코드도 변경해야할 가능성이 높이집니다.

  2. 서비스 로직에 의해 의도 되지않은 서비스 성공 또는 실패가 발생할 수 있습니다.

  3. 테스트 해야할 검증대상(서비스)을 내가 만든 서비스를 통해 테스트를 한다는 것 자체가 모순이됩니다. 예를들어 집을 짓기위해 포크레인을 만들고 포크레인이 잘 작동하는지 테스트를 해야하는데 내가 만든 포크레인으로 새로만든 포크레인을 테스트 하는 것 자체가 모순이지요. 물론 Repository 부분도 테스트가 필요하겠지만 최대한 변경여지가 없게, Raw하게 데이터를 준비할 수 있는 방법에서는 Repository(.save)가 적당합니다.

 

다른 잼난 비유로 생각해보자면

회사 돈 50억을 횡령한 직원이있다고 생각해봅시당. 그 사람은 경찰 조사에서 총 30억을 탕진해서 20억 밖에 안남았다고 주장합니다. 그렇다면 경찰은 그 사람의 주머니(Service)에서 나온 20억을 그대로 믿어야 할까요? 아니면 통장(Repository)내역을 통해 검증을 해야할까요?

 

감사합니다.

전병준님의 프로필 이미지
전병준
질문자

답변 감사합니다 ㅎㅎ 그렇다면 궁금한 점이 저처럼 Controller 에서 한꺼번에 통합 테스트를 한다고 하면 당연히 다른 레이어와 의존이 생기는게 아닐까요 ? (클라이언트 요청이 오면 Controller -> Repository 흐름이 아닌 Controller -> Service -> Repository 흐름을 거치도록 하니까 ???) 아니면 이렇게 End-To-End 방식으로 테스트하는게 권장되는 방법이 아닌건지, Controller 테스트와 Service 테스트를 나누는 기준..? 그런걸 잘 모르겠네요 🥲

 

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

안녕하세요. 호돌맨입니다.

(지금보니 제가 질문을 잘 이해 못한것 같기도하고요.. 혹시 이상하면 다시 댓글 부탁드려용 ㅎㅎ 의문이 드는 부분을 코드로 간략히 올려주시면 더 좋을것 같아용!)

컨트롤러에서 끝단 테스트를 진행하게 된다면 당연히 서비스쪽 코드도 테스트가 진행될텐데요(당연한 의존성이 생기는 부분이겠죠)

다만 테스트를 위해 준비되는 데이터(주로 given쪽 위치)와 검증하기위한 데이터(주로 then에 위치)는 테스트하려는 대상과의 의존성을 어느정도는 분리해서 해야하지 않냐는 얘기였습니다.

 

전병준님의 프로필 이미지
전병준
질문자

그럼 호돌맨님 현재 강의에서 진행하는 Controller 테스트는 통합 테스트 용도가 딱히 아닌거고.. 단위 테스트(슬라이스 테스트?? 이 용어가 맞는지는 잘 모르겠습니다.) 와 비슷하다고 할 수 있을 것 같다고 생각하는데 이게 맞을까요 ? 맞다면 통합 테스트가 아니니까 굳이 Service 레이어를 의존할 필요가 없는거구 그래서 Repository 를 바로 사용한 것이 아닌가 라는 생각이 드네용 ㅎㅎ

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

통합테스트입니다.

제가 레파지토리를 이용한다는 게 소스에서 어떤 부분인지 스샷이나 소스로 보여주실 수 있나요?

전병준님의 프로필 이미지
전병준
질문자

넵 글 1개 조회 테스트에서, PostRepository 의 save() 호출 부분을 보고 사용했다고 생각했습니다.

postRepository.save(post);
@Test
    @DisplayName("글 1개 조회")
    void test4() throws Exception {
        // given
        Post post = Post.builder()
                .title("123456789012345")
                .content("bar")
                .build();

        postRepository.save(post);

        // expected
        mockMvc.perform(get("/posts/{postId}", post.getId())
                        .contentType(APPLICATION_JSON))
                .andExpect(status().isOk())
                .andExpect(jsonPath("$.id").value(post.getId()))
                .andExpect(jsonPath("$.title").value("1234567890"))
                .andExpect(jsonPath("$.content").value("bar"))
                .andDo(print());
    }
호돌맨님의 프로필 이미지
호돌맨
지식공유자

repository.save하는 부분은 조회할 데이터를 준비하는 부분이고요

실질적으로 테스트 대상이 되는 부분은 expected부터 나오는 mockMvc호출이겠죠. 그러면 실제로 controller, 서비스, reppsitory 레이어를 거치면서 비즈니스 로직에 맞게 코드가 실행 될테니깐요.

이 전에 말씀드린대로 repository를 통해 데이터를 준비하는 이유는 비즈니스 로직에 최대한 의존적이지 않게 하려는 거고요.

전병준님의 프로필 이미지
전병준
질문자

아 MockMvc 호출할 때 Controller -> Service -> Repository 흐름으로 로직이 실행되니 given 데이터 준비할 때 굳이 Service 레이어에 의존해서 할 필요가 없어서 분리라고 말씀하신 거였군요 ㅠㅠㅠㅠ 빠른 답변 정말 감사합니다!! 테스트 코드 수정해야할 것 같네요 ㅋㅋㅎㅎ

전병준님의 프로필 이미지
전병준

작성한 질문수

질문하기