스프링과 JPA 기반 웹 애플리케이션 개발 #15 회원 가입 인증 메일 확인 테스트 및 리팩토링

Jake Seo·2021년 5월 28일
0

스프링과 JPA 기반 웹 애플리케이션 개발 #15 회원 가입 인증 메일 확인 테스트 및 리팩토링

해당 내용은 인프런, 스프링과 JPA 기반 웹 애플리케이션 개발의 강의 내용을 바탕으로 작성된 내용입니다.

강의를 학습하며 요약한 내용을 출처를 표기하고 블로깅 또는 문서로 공개하는 것을 허용합니다 라는 원칙 하에 요약 내용을 공개합니다. 출처는 위에 언급되어있듯, 인프런, 스프링과 JPA 기반 웹 애플리케이션 개발입니다.

제가 학습한 소스코드는 https://github.com/n00nietzsche/jakestudy_webapp 에 지속적으로 업로드 됩니다. 매 커밋 메세지에 강의의 어디 부분까지 진행됐는지 기록해놓겠습니다.


회원 가입 인증 메일 확인 테스트 및 리팩토링

테스트

  • 입력 값이 잘못된 경우
    • error 프로퍼티가 model에 들어있는지 확인
    • 뷰 이름이 account/checked-email 인지 확인
  • 입력 값이 올바른 경우
    • 모델에 error가 없는지 확인
    • 모델에 numberOfUser가 있는지 확인
    • 모델에 nickname이 있는지 확인
    • 뷰 이름 확인

리팩토링

  • 코드의 위치가 적절한가?

AccountController 코드 변경

accountService.completeSignUp(account);

회원가입 이후에 emailVerifiedtrue로 바꿔주는 부분과 jointedAt을 현재 시각으로 바꿔주는 부분을 서비스쪽으로 넘김. 관심사의 분리.

스택오버플로에서 좋은 글을 읽었다.

The controller responsibility is to get the parameter requests, and then call one or more service methods and combine the results in a response that is then sent back to the client.

https://stackoverflow.com/questions/23118789/why-we-shouldnt-make-a-spring-mvc-controller-transactional

AccountService 코드 변경

    @Transactional
    public void completeSignUp(Account account) {
        account.completeSignUp();
    }

completeSignUp()이라는 메소드를 추가하여 회원가입 이후 절차에 대한 실행 코드를 만들었다. 그 세부 내용은 오직 도메인과 관련된 내용이라 도메인 내부로 넣어놨다.

Account 코드 변경

    public void completeSignUp() {
        this.setEmailVerified(true);
        this.setJoinedAt(LocalDateTime.now());
    }

.completeSignUp()이 호출되면 이메일 인증 정보를 true로 바꾸고, 회원 가입 일자를 현재 시각으로 바꾼다.

AccountControllerTest 코드 변경

    @DisplayName("인증 메일 확인 - 입력값 오류")
    @Test
    void checkEmailTokenWithWrongInput() throws Exception {
        mockMvc.perform(get("/check-email-token")
                .param("token", "it's wrong token")
                .param("email", "email@email.com"))
                .andExpect(status().isOk())
                .andExpect(model().attributeExists("error"))
                .andExpect(view().name("account/checked-email"));
    }

    @DisplayName("인증 메일 확인 - 입력값 정상")
    @Test
    void checkEmailTokenWithCorrectInput() throws Exception {
        // 회원가입 이후
        if(!accountRepository.existsByEmail(testEmail)){
            signUpSubmitWithCorrectInput();
        }

        Account newAccount = accountRepository.findByEmail(testEmail);

        mockMvc.perform(get("/check-email-token")
                .param("token", newAccount.getEmailCheckToken())
                .param("email", newAccount.getEmail()))
                .andExpect(status().isOk())
                .andExpect(model().attributeDoesNotExist("error"))
                .andExpect(model().attributeExists("nickname"))
                .andExpect(model().attributeExists("numberOfUser"))
                .andExpect(view().name("account/checked-email"));

        // 가입일자가 생겨야 함
        // @Transactional 애노테이션 없으면 detached 된 상태로 JPA 객체를 불러오는 것에 주의해야 함
        // 일단 detached 상태로 JPA 객체를 불러오면 컨트롤러 단과 같은 곳에서 올바르게 객체를 수정해도
        // JPA 객체 수정이 반영되지 않는다.
        // 그러므로 up-to-date 상태의 JPA 객체를 가지고 있고 싶으면 @Transactional 이 필요하다.
        // 그리고 또한 관심사의 분리로 컨트롤러 단에 @Transactional 붙이는 건 좋지 않다.
        // https://stackoverflow.com/questions/23118789/why-we-shouldnt-make-a-spring-mvc-controller-transactional
        assertNotNull(newAccount.getJoinedAt());
    }
  • 이메일 인증에 올바르지 않은 값을 넣었을 때
  • 회원가입 이후 이메일 인증에 올바른 값을 넣었을 때

두 개의 케이스에 대해 작성하였다.

그리고 @Transactional의 중요성에 대해 배웠는데, @Transactional이 없는 곳에서 JPA 객체를 불러오면, 그 객체는 애플리케이션 내부에서 변경되었을 때, 동기화되지 않는다는 것을 알았다.

detached된 객체는 처음 불러온 이후 업데이트되지 않는 것에 대해 항상 인지하자.

profile
풀스택 웹개발자로 일하고 있는 Jake Seo입니다. 주로 Jake Seo라는 닉네임을 많이 씁니다. 프론트엔드: Javascript, React 백엔드: Spring Framework에 관심이 있습니다.

0개의 댓글