빙응의 공부 블로그
[Spring]단위 테스트 정리하기 Mockito 실습 (3/3) 본문
[Spring]단위 테스트 정리하기 JUnit(1/3) (tistory.com)
[Spring]단위 테스트 정리하기 Mockito (2/3) (tistory.com)
📝실습할 코드
실습 코드는 현재 진행하는 프로젝트에서 가져왔고
매우 어려운 부분을 가져왔습니다..
해당 코드는 프로젝트에서 가져온 학교 인증 비즈니스 로직입니다.
@Service
@RequiredArgsConstructor
@Slf4j
public class UniversityVerificationService {
private final JavaMailSender javaMailSender;
private final UniversityVerificationRepository universityVerificationRepository;
@Value("${spring.mail.username}")
private String serviceName;
private final MemberRepository memberRepository;
// 6자리 난수 생성
private String makeRandomNum() {
Random r = new Random();
StringBuilder randomNumber = new StringBuilder();
for (int i = 0; i < 6; i++) {
randomNumber.append(r.nextInt(10));
}
return randomNumber.toString();
}
/* 이메일 전송 */
public void mailSend(String toMail, String title, String content) {
MimeMessage message = javaMailSender.createMimeMessage();
try {
message.setFrom(serviceName); // 발신자 이메일 설정
message.setRecipients(MimeMessage.RecipientType.TO, toMail); // 수신자 이메일 설정
message.setSubject(title); // 이메일 제목 설정
// 이메일 본문 설정 (HTML 형식)
message.setText(content, "UTF-8", "html");
// 이메일 전송
javaMailSender.send(message);
} catch (MessagingException e) {
throw new CustomException(MailErrorCode.FAILED_MAIL_SEND);
}
}
/* 이메일 작성 및 인증 코드 저장 */
public void sendVerificationEmail(String email) {
String authNumber = makeRandomNum(); // 난수 생성
String title = "회원 가입을 위한 이메일입니다!";
String content = "이메일을 인증하기 위한 절차입니다." +
"<br><br>" +
"인증 번호는 " + authNumber + "입니다." +
"<br>" +
"회원 가입 폼에 해당 번호를 입력해주세요.";
mailSend(email, title, content);
// Redis에 인증 코드 저장
UniversityVerification verification = UniversityVerification.builder()
.email(email)
.authCode(authNumber)
.expiration(180L)
.build();
universityVerificationRepository.save(verification); // Redis에 저장
}
/* 재요청 메서드 */
public void reRequest(String email) {
universityVerificationRepository.deleteByEmail(email); // 기존 데이터 삭제
sendVerificationEmail(email); // 동일한 메서드 호출로 재요청
}
/* 인증 코드 검증 메서드 */
public void verifyAuthCode(String email, String code, Long id) {
UniversityVerification verification = universityVerificationRepository.findByEmail(email)
.orElseThrow(() -> new CustomException(MemberErrorCode.UNIVERSITY_VERIFICATION_NOT_FOUND));
if (verification.getAuthCode().equals(code)) {
Member member = memberRepository.findById(id)
.orElseThrow(() -> new CustomException(MemberErrorCode.MEMBER_NOT_FOUND));
member.setAuth(true);
memberRepository.save(member);
} else {
throw new CustomException(MemberErrorCode.INVALID_AUTH_CODE);
}
}
}
📝 테스트 진행하기
의존성 설정
@ExtendWith(MockitoExtension.class)
public class UniversityVerificationServiceTest {
@Mock
private JavaMailSender javaMailSender;
@Mock
private UniversityVerificationRepository universityVerificationRepository;
@Mock
private MemberRepository memberRepository;
@InjectMocks
private UniversityVerificationService universityVerificationService;
private static final String EMAIL = "quddnddl35@naver.com";
private static final Long MEMBER_ID = 1L;
해당 서비스는 인자로 javaMailSender, universityVerificationRepository, memberRepository를 가져오므로 3가지를 목으로 지정했습니다. 또한 로직에 필요한 EMAIL과 MEMBER_ID를 미리 지정했습니다.
이메일 전송 메소드 테스트
/* 이메일 전송 */
public void mailSend(String toMail, String title, String content) {
MimeMessage message = javaMailSender.createMimeMessage();
try {
message.setFrom(serviceName); // 발신자 이메일 설정
message.setRecipients(MimeMessage.RecipientType.TO, toMail); // 수신자 이메일 설정
message.setSubject(title); // 이메일 제목 설정
// 이메일 본문 설정 (HTML 형식)
message.setText(content, "UTF-8", "html");
// 이메일 전송
javaMailSender.send(message);
} catch (MessagingException e) {
log.error("Failed to send email to: {}. Error: {}", toMail, e.getMessage());
throw new CustomException(MailErrorCode.FAILED_MAIL_SEND);
}
}
/* 이메일 작성 및 인증 코드 저장 */
public void sendVerificationEmail(String email) {
String authNumber = makeRandomNum(); // 난수 생성
String title = "회원 가입을 위한 이메일입니다!";
String content = "이메일을 인증하기 위한 절차입니다." +
"<br><br>" +
"인증 번호는 " + authNumber + "입니다." +
"<br>" +
"회원 가입 폼에 해당 번호를 입력해주세요.";
mailSend(email, title, content);
// Redis에 인증 코드 저장
UniversityVerification verification = UniversityVerification.builder()
.email(email)
.authCode(authNumber)
.expiration(180L)
.build();
universityVerificationRepository.save(verification); // Redis에 저장
}
이메일 전송 메소드입니다. 해당 메소드를 검증하기 위해서는 2가지 Verif 작업이 필요합니다.
- sendVerificationEmail - universityVerificationRepository.save : Redis 저장 메소드가 잘 호출되는지 검사
- mailSend - javaMailSender.send : 메일이 전달되었는지 검사
@Test
public void testSendVerificationEmail() {
// given
MimeMessage message = Mockito.mock(MimeMessage.class); // MimeMessage Mock 생성
when(javaMailSender.createMimeMessage()).thenReturn(message); // createMimeMessage 메서드 Mock 설정
doNothing().when(javaMailSender).send(any(MimeMessage.class)); // 이메일 전송 메서드 Mock 설정
// when
universityVerificationService.sendVerificationEmail(EMAIL);
// then
verify(javaMailSender, times(1)).send(any(MimeMessage.class)); // 이메일 전송이 호출되었는지 검증
verify(universityVerificationRepository, times(1)).save(any(UniversityVerification.class)); // Redis 저장이 호출되었는지 검증
}
// given
MimeMessage message = Mockito.mock(MimeMessage.class); // MimeMessage Mock 생성
when(javaMailSender.createMimeMessage()).thenReturn(message); // createMimeMessage 메서드 Mock 설정
doNothing().when(javaMailSender).send(any(MimeMessage.class)); // 이메일 전송 메서드 Mock 설정
MinmeMesage 목을 생성하는 이유는 javaMailSender 메소드 자체가 패키지로 있기 때문에 해줘야 합니다.
universityVerificationService.sendVerificationEmail 호출 시에 동작하는 javaMailSender를 Mock으로 만듭니다.
그 이유는 실제로 동작하기 때문에 이것을 목으로 만들어 주는 것입니다. 그래서 실제 동작에서 실행되는 것은
Redis 저장밖에 없습니다.
이메일 검증 코드 테스트
/* 인증 코드 검증 메서드 */
public void verifyAuthCode(String email, String code, Long id) {
UniversityVerification verification = universityVerificationRepository.findByEmail(email)
.orElseThrow(() -> new CustomException(MemberErrorCode.UNIVERSITY_VERIFICATION_NOT_FOUND));
if (verification.getAuthCode().equals(code)) {
Member member = memberRepository.findById(id)
.orElseThrow(() -> new CustomException(MemberErrorCode.MEMBER_NOT_FOUND));
member.setAuth(true);
memberRepository.save(member);
} else {
throw new CustomException(MemberErrorCode.INVALID_AUTH_CODE);
}
}
- 이메일 검증 성공 시
@Test
public void testVerifyAuthCode_Success() {
// given
String authCode = "123456";
UniversityVerification verification = new UniversityVerification();
verification.setEmail(EMAIL);
verification.setAuthCode(authCode);
when(universityVerificationRepository.findByEmail(EMAIL)).thenReturn(Optional.of(verification));
Member member = new Member();
member.setId(MEMBER_ID);
when(memberRepository.findById(MEMBER_ID)).thenReturn(Optional.of(member));
// when
universityVerificationService.verifyAuthCode(EMAIL, authCode, MEMBER_ID);
// then
assertThat(member.isAuth()).isTrue(); // 회원 인증 상태 검증
verify(memberRepository, times(1)).save(member); // 멤버 저장이 호출되었는지 검증
}
한번 요령을 터득하면 보일 것입니다. 해당 메소드에서 조회 관련을 모두 임의의 가짜 데이터로 바꾸고 Member를 바꾸는 로직만 실행하는 것을 볼 수 있습니다.
- 이메일 검증 실패 시
@Test
public void testVerifyAuthCode_Failure() {
// given
UniversityVerification verification = new UniversityVerification();
verification.setEmail(EMAIL);
verification.setAuthCode("wrongCode");
// when
when(universityVerificationRepository.findByEmail(EMAIL)).thenReturn(Optional.of(verification));
// then
assertThatThrownBy(() -> universityVerificationService.verifyAuthCode(EMAIL, "123456", MEMBER_ID))
.isInstanceOf(CustomException.class);
}
이메일 검증 실패 시에는 오류를 리턴하기에 오류가 발생 했는지 검사합니다.
✔참고
[Spring] JUnit과 Mockito 기반의 Spring 단위 테스트 코드 작성법 (3/3) - MangKyu's Diary (tistory.com)
[Spring] JUnit과 Mockito 기반의 Spring 단위 테스트 코드 작성법 (3/3)
이번에는 Spring 기반의 웹 애플리케이션에서 테스트를 작성하는 방법에 대해 알아보도록 하겠습니다. 1. Mockito 소개 및 사용법 [ Mockito란? ] Mockito는 개발자가 동작을 직접 제어할 수 있는 가짜 객
mangkyu.tistory.com
'Spring > 개인공부_이론' 카테고리의 다른 글
[Spring]스프링의 트랜잭션 전파 속성 (2) | 2024.12.03 |
---|---|
[Spring]OpenFeign (0) | 2024.10.20 |
[Spring]단위 테스트 정리하기 Mockito (2/3) (1) | 2024.10.18 |
[Spring]단위 테스트 정리하기 JUnit(1/3) (1) | 2024.10.18 |
[Spring API]Spring WebFlux와 WebClient (0) | 2024.05.24 |