스프링과 JPA 기반 웹 애플리케이션 개발 #15 회원 가입 인증 메일 확인 테스트 및 리팩토링
해당 내용은 인프런, 스프링과 JPA 기반 웹 애플리케이션 개발의 강의 내용을 바탕으로 작성된 내용입니다.
강의를 학습하며 요약한 내용을 출처를 표기하고 블로깅 또는 문서로 공개하는 것을 허용합니다 라는 원칙 하에 요약 내용을 공개합니다. 출처는 위에 언급되어있듯, 인프런, 스프링과 JPA 기반 웹 애플리케이션 개발입니다.
제가 학습한 소스코드는 https://github.com/n00nietzsche/jakestudy_webapp 에 지속적으로 업로드 됩니다. 매 커밋 메세지에 강의의 어디 부분까지 진행됐는지 기록해놓겠습니다.
accountService.completeSignUp(account);
회원가입 이후에 emailVerified
를 true
로 바꿔주는 부분과 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.
@Transactional
public void completeSignUp(Account account) {
account.completeSignUp();
}
completeSignUp()
이라는 메소드를 추가하여 회원가입 이후 절차에 대한 실행 코드를 만들었다. 그 세부 내용은 오직 도메인과 관련된 내용이라 도메인 내부로 넣어놨다.
public void completeSignUp() {
this.setEmailVerified(true);
this.setJoinedAt(LocalDateTime.now());
}
.completeSignUp()
이 호출되면 이메일 인증 정보를 true
로 바꾸고, 회원 가입 일자를 현재 시각으로 바꾼다.
@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
된 객체는 처음 불러온 이후 업데이트되지 않는 것에 대해 항상 인지하자.