2021-01-18 :: 의존하는 객체에 대한 테스트 코드 고찰

구현 코드들을 대량 수정하면서 테스트 코드들이 여러 깨지게 됐다. 해당 테스트 코드들을 고치면서 느낀점이 서비스 레이어 단에서 mapper 클래스가 계속 사용되게 되는데 이 모든걸을 mock 객체로 두면 매번 given으로 정의를 해줘야한다. 동작을 정의 해주면서 mapper가 들어가기 이전 값과 결과 값을 계속해서 생성하게 되는 코드가 반복되는데 해당 코드들을 줄이기로 했다.

일단 모든 테스트 코드는 도메인 단위로 작성하도록 하고 있다. 이제 도메인 단위에서 Mapper의 테스트 코드를 작성하고 Mapper 테스트 코드가 정상적으로 동작하게 되면 서비스 레이어에서 테스트 코드를 작성할 때 사용되는 Mapper 객체를 목 객체가 아닌 구현 객체로 테스트 한다. 이렇게 변경하게되면서 테스트 코드에 중복되는 많은 코드들을 줄일 수 있게 되었다.

간단하게 예를 들면 아래가 mapper 클래스를 mock 객체로 둔 이전의 테스트 코드이다.

@Test
    void getDetailDTOById() throws Exception {
        //given
        Long id = 0L;
        User user = User.builder()
                .id(id)
                .name("testName")
                .pw("testPw")
                .email("0L")
                .build();

        UserDetailDTO userDetailDTOTemp = UserDetailDTO.builder()
                .id(id)
                .name("testName")
                .build();

        given(userRepository.findById(id)).willReturn(Optional.of(user));
        given(userToUserDetailDtoMapper.entityToUserDetailDTO(any(User.class))).willReturn(userDetailDTOTemp);

        //when
        UserDetailDTO userDetailDTO = getUserService.getDetailDTOById(id);

        //then
        assertThat(userDetailDTO).isNotNull();
    }

아래 코드가 mapper 테스트 코드를 먼저 작성하고 정상적으로 동작된다는 가정하에 mapper 클래스를 mock이 아닌 구현 객체를 사용한것이다. 많은 양의 코드가 줄어들게 되었으며 다른 테스트 코드에서 중복되는 코드들을 줄일 수 있었다.

@Test
    @DisplayName("아이디로 UserDetailDTO를 반환하는 테스트")
    void getDetailDTOById() {
        //given
        GetUserService getUserService = new GetUserService(userRepository, userToUserDetailDtoMapper);

        long userId = 0L;
        given(userRepository.findById(anyLong())).willReturn(Optional.of(DomainFactory.createUser(userId)));

        //when
        UserDetailDTO userDetailDTO = getUserService.getDetailDTOById(userId);

        //then
        assertThat(userDetailDTO).isNotNull();
    }

프로젝트를 진행을 하면서 많은 코드들을 수정하게 되고 프로그램의 사이즈가 커질 수록(그렇게 큰건 아니지만) 의존하는 객체들이 여럿 생겨나게 된다. 테스트 코드 작성시 의존하는 객체들은 모두 mocking을 하기에 테스트 코드를 작성할때마다 중복되는 코드가 많이 생기게 되고 테스트 코드를 작성하는 시간 때문에 개발 속도에도 큰 영향을 주게 되었다.

해결책으로 선택한 나의 방법은 어느정도의 의존 객체를 모두 mocking 하지 않고 구현 객체로 사용하는것이다. 이 방법을 선택하고 난 후 테스트 코드의 중복 코드가 줄어들고 개발 속도가 높아지는 이점을 주었다.

(만약 이 부분(서비스 레이어)에서 에러가 발생하더라도 실제로 의존하는 객체는 mapper객체들 뿐이고 나머지는 모두 mock 객체이기 때문에 mapper와 서비스 코드에서 에러를 확인하면 된다. 테스트 코드에 의존하는 부분들을 잘 정리해 두면 나중에 다른 팀원이 참가하게 됐을때나 코드를 변경하면서 발생하는 에러를 찾을때 실제 구현 객체에 의존하는 객체들만 확인 해보면 된다. )