2021-01-24 :: 테스트 코드 수정 완료 및 변경점

테스트 코드 작성시 불편했던 점

TestingResult.png

며칠 동안 많은 양의 테스트 코드들을 수정완료 했다.

문제는 서비스레이어에서 테스트 작성시 아래 코드와 같은 관계를 가진 상태를 만들어 주어야했다. 처음 진행할때는 Entity 관계가 깊지 않아 테스트 코드 작성시 문제가 되지 않았는데 프로젝트를 진행함에 따라 깊어지는 도메인간의 관계를 작성하는것은 큰 불편함이 있었다. 이러한 상태를 매번 작성하는것이 무의미함과 동시에 중복된 코드가 대량 발생하고 테스트 코드 작성시 너무 많은 시간이 걸렸다. 이러한 문제를 해결하기위해 Factory패턴이라고 해야할까.. 상태를 미리 만들어놓고 필요한 도메인들을 골라서 사용하기로 하였다.

변경 전 코드

	@Test
    @DisplayName("일반 권한 사용자가 그룹 단어장의 DTO를 정상적으로 반환하는 테스트")
    void getDetailDTOByUserIdAndStudyGroupIdAndWordBookId1() {
        //given
        User user = User.builder()
                .id(0L)
                .name("testName")
                .email("testEmail@test.com")
                .pw("testPw")
                .build();

        StudyGroup studyGroup = StudyGroup.builder()
                .id(1L)
                .isUsing(true)
                .name("testStudyGroupName")
                .build();

        Study study = Study.builder()
                .id(3L)
                .isUsing(true)
                .user(user)
                .studyGroup(studyGroup)
                .studyGroupRole(StudyGroupRole.NORMAL)
                .build();

        user.joinToStudy(study);
        studyGroup.addStudy(study);

        StudyGroupWordBook studyGroupWordBook = StudyGroupWordBook.builder()
                .id(4L)
                .isUsing(true)
                .name("testWordBookName")
                .studyGroup(studyGroup)
                .build();

        studyGroup.addWordBook(studyGroupWordBook);

        given(getStudyService.getEntityByFindByUserIdAndStudyGroupsId(anyLong(), anyLong())).willReturn(study);

        Long userId = study.getUser().getId();
        Long studyGroupId = study.getStudyGroup().getId();
        Long wordBookId = studyGroupWordBook.getId();

        //when
        WordBookDetailDTO wordBookDetailDTO = getStudyGroupWordBookService.getDetailDTOByUserIdAndStudyGroupIdAndWordBookId(userId, studyGroupId, wordBookId);

        //then
        assertThat(wordBookDetailDTO).isNotNull();
        assertThat(wordBookDetailDTO.getId()).isEqualTo(wordBookId);
    }

수정 후

DomainFactory라는 클래스를 만든 후 모든 Domain간의 관계가 형성된 상태를 만든다( 상태라는 말이 맞나??)

이후 테스트 코드에서 필요한 도메인을 받아서 쓰도록 만들었다. 이렇게 만들어보니 테스트 코드 작성시 계속 해서 만들어야하는 entity들을 바로 꺼내서 테스트 돌려볼 수 있어서 테스트 코드 양도 줄어들고 작성 시간도 줄어들게 됐다.

DomainFactory

아래 코드 처럼 생성시 모든 관계를 형성하는 상태를 만든 후 getter를 이용하여 사용한다.

@Component
public class DomainFactory {

    private final User userOfStudyGroupAdmin;
    private final User userOfStudyGroupNormal;
    private final Study studyOfStudyGroupAdmin;
    private final Study studyOfStudyGroupNormal;
    private final StudyGroup studyGroup;
    private final StudyGroupWordBook studyGroupWordBook;
    private final UserWordBook userWordBookOfAdminUser;
    private final UserWordBook userWordBook;

    public DomainFactory() {
        userOfStudyGroupAdmin = createUser(0L);
        userOfStudyGroupNormal = createUser(1L);

        studyGroup = createStudyGroup(0L);

        studyOfStudyGroupAdmin = createStudyOfNormalUser(0L, studyGroup, userOfStudyGroupNormal);
        userOfStudyGroupAdmin.joinToStudy(studyOfStudyGroupAdmin);
        studyGroup.addStudy(studyOfStudyGroupAdmin);

        studyOfStudyGroupNormal = createStudyOfAdminUser(1L, studyGroup, userOfStudyGroupNormal);
        userOfStudyGroupNormal.joinToStudy(studyOfStudyGroupNormal);
        studyGroup.addStudy(studyOfStudyGroupNormal);

        studyGroupWordBook = createStudyGroupWordBook(0L, studyGroup);
        studyGroup.addWordBook(studyGroupWordBook);

        userWordBookOfAdminUser = createUserWordBook(0L, userOfStudyGroupAdmin);
        userOfStudyGroupAdmin.addWordBook(userWordBookOfAdminUser);

        userWordBook = createUserWordBook(1L, userOfStudyGroupNormal);
        userOfStudyGroupNormal.addWordBook(userWordBook);

        int length = 4;
        LongStream.range(0, length).forEach(i -> {
            studyGroupWordBook.addWord(createWord(i));

            userWordBookOfAdminUser.addWord(createWord(i));
            userWordBook.addWord(createWord(i));
        });
    }

//이후는 getter 코드...

변경 후 코드

DomainFactory를 이용하여 작성한 테스트 코드를 보면 아래와 같이 변경 됐다.

	@Test
    @DisplayName("일반 권한 사용자가 그룹 단어장의 DTO를 정상적으로 반환하는 테스트")
    void getDetailDTOByUserIdAndStudyGroupIdAndWordBookId() {
        //given
        Study study = domainFactory.getStudyOfStudyGroupNormal();
        StudyGroupWordBook studyGroupWordBook = domainFactory.getStudyGroupWordBook();

        given(getStudyService.getEntityByFindByUserIdAndStudyGroupsId(anyLong(), anyLong())).willReturn(study);

        Long userId = study.getUser().getId();
        Long studyGroupId = study.getStudyGroup().getId();
        Long wordBookId = studyGroupWordBook.getId();

        //when
        WordBookDetailDTO wordBookDetailDTO = getStudyGroupWordBookService.getDetailDTOByUserIdAndStudyGroupIdAndWordBookId(userId, studyGroupId, wordBookId);

        //then
        assertThat(wordBookDetailDTO).isNotNull();
        assertThat(wordBookDetailDTO.getId()).isEqualTo(wordBookId);
    }

코드가 훨씬 간결해지고 어떤 테스트 코드를 작성하던 원하는 도메인만 골라서 사용하면 된다. 훨씬 줄어든 코드량으로 빠르게 테스트 코드들을 수정할 수 있었다. 변경된 방식으로 테스트 코드를 작성하게 되면서 테스트 코드 수정에 부담감이 많이 사라지게 됐다.

다음 진행은 spring security를 학습하여 로그인과 사용자 인증관련된 기능을 추가를 해보도록 하겠다.

(이걸 해야 그룹에서 원하는 상대를 초대할때 내가 초대한 사용자가 맞는지 확인을 할 수 있을것 같다, 현재까지 구현한 유저 도메인이 통째로 변경될텐데… ㅜ)