add testcode

This commit is contained in:
ondal
2025-02-14 16:51:26 +09:00
parent d7ca5994b4
commit 2f672a8ea5
40 changed files with 1517 additions and 9 deletions
@@ -0,0 +1,122 @@
package com.unicorn.lifesub.member.test.unit.config.jwt;
import com.unicorn.lifesub.member.config.jwt.CustomUserDetailsService;
import com.unicorn.lifesub.member.repository.entity.MemberEntity;
import com.unicorn.lifesub.member.repository.jpa.MemberRepository;
import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
import org.mockito.InjectMocks;
import org.mockito.Mock;
import org.mockito.junit.jupiter.MockitoExtension;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UsernameNotFoundException;
import java.util.HashSet;
import java.util.Optional;
import java.util.Set;
import static org.assertj.core.api.Assertions.assertThat;
import static org.junit.jupiter.api.Assertions.assertThrows;
import static org.mockito.BDDMockito.given;
/**
* 사용자 상세 정보 서비스 테스트 클래스
* Spring Security의 UserDetailsService 구현체 검증
*/
@ExtendWith(MockitoExtension.class)
class CustomUserDetailsServiceTest {
@InjectMocks
private CustomUserDetailsService userDetailsService;
@Mock
private MemberRepository memberRepository;
// 테스트용 상수 정의
private static final String TEST_USER_ID = "testUser";
private static final String TEST_PASSWORD = "testPassword";
private static final String TEST_USER_NAME = "Test User";
/**
* 사용자 조회 성공 케이스 테스트
* 존재하는 사용자 ID로 조회 시 UserDetails 객체가 정상적으로 반환되는지 검증
*/
@Test
@DisplayName("givenExistingUserId_whenLoadUser_thenReturnUserDetails")
void givenExistingUserId_whenLoadUser_thenReturnUserDetails() {
// Given
MemberEntity memberEntity = createTestMemberEntity();
given(memberRepository.findByUserId(TEST_USER_ID)).willReturn(Optional.of(memberEntity));
// When
UserDetails userDetails = userDetailsService.loadUserByUsername(TEST_USER_ID);
// Then
assertThat(userDetails).isNotNull();
assertThat(userDetails.getUsername()).isEqualTo(TEST_USER_ID);
assertThat(userDetails.getPassword()).isEqualTo(TEST_PASSWORD);
assertThat(userDetails.getAuthorities()).hasSize(1);
}
/**
* 사용자 조회 실패 케이스 테스트
* 존재하지 않는 사용자 ID로 조회 시 적절한 예외가 발생하는지 검증
*/
@Test
@DisplayName("givenNonExistentUserId_whenLoadUser_thenThrowException")
void givenNonExistentUserId_whenLoadUser_thenThrowException() {
// Given
String nonExistentUserId = "nonexistent";
given(memberRepository.findByUserId(nonExistentUserId)).willReturn(Optional.empty());
// When & Then
assertThrows(UsernameNotFoundException.class, () ->
userDetailsService.loadUserByUsername(nonExistentUserId));
}
/**
* 사용자 권한 매핑 테스트
* 사용자의 역할이 Spring Security 권한으로 올바르게 매핑되는지 검증
*/
@Test
@DisplayName("givenUserWithRoles_whenLoadUser_thenMapAuthoritiesCorrectly")
void givenUserWithRoles_whenLoadUser_thenMapAuthoritiesCorrectly() {
// Given
MemberEntity memberEntity = createTestMemberEntityWithMultipleRoles();
given(memberRepository.findByUserId(TEST_USER_ID)).willReturn(Optional.of(memberEntity));
// When
UserDetails userDetails = userDetailsService.loadUserByUsername(TEST_USER_ID);
// Then
assertThat(userDetails.getAuthorities()).hasSize(2);
assertThat(userDetails.getAuthorities())
.extracting("authority")
.containsExactlyInAnyOrder("USER", "ADMIN");
}
// 테스트 헬퍼 메서드
private MemberEntity createTestMemberEntity() {
Set<String> roles = new HashSet<>();
roles.add("USER");
return MemberEntity.builder()
.userId(TEST_USER_ID)
.userName(TEST_USER_NAME)
.password(TEST_PASSWORD)
.roles(roles)
.build();
}
private MemberEntity createTestMemberEntityWithMultipleRoles() {
Set<String> roles = new HashSet<>();
roles.add("USER");
roles.add("ADMIN");
return MemberEntity.builder()
.userId(TEST_USER_ID)
.userName(TEST_USER_NAME)
.password(TEST_PASSWORD)
.roles(roles)
.build();
}
}
@@ -0,0 +1,148 @@
package com.unicorn.lifesub.member.test.unit.config.jwt;
import com.auth0.jwt.JWT;
import com.auth0.jwt.algorithms.Algorithm;
import com.unicorn.lifesub.common.dto.JwtTokenDTO;
import com.unicorn.lifesub.common.exception.InfraException;
import com.unicorn.lifesub.member.config.jwt.JwtTokenProvider;
import com.unicorn.lifesub.member.repository.entity.MemberEntity;
import jakarta.servlet.http.HttpServletRequest;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.Test;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.authority.SimpleGrantedAuthority;
import java.util.Collections;
import java.util.HashSet;
import java.util.Set;
import static org.assertj.core.api.Assertions.assertThat;
import static org.junit.jupiter.api.Assertions.assertThrows;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.when;
/**
* JWT 토큰 제공자 테스트 클래스
* 토큰 생성, 검증, 파싱 등의 기능을 검증
*/
class JwtTokenProviderTest {
private JwtTokenProvider jwtTokenProvider;
private static final String SECRET_KEY = "test-secret-key";
private static final long ACCESS_TOKEN_VALIDITY = 3600000;
private static final long REFRESH_TOKEN_VALIDITY = 86400000;
@BeforeEach
void setUp() {
jwtTokenProvider = new JwtTokenProvider(SECRET_KEY, ACCESS_TOKEN_VALIDITY, REFRESH_TOKEN_VALIDITY);
}
/**
* 토큰 생성 테스트
* 유효한 사용자 정보로 JWT 토큰이 정상적으로 생성되는지 검증
*/
@Test
@DisplayName("givenValidMember_whenCreateToken_thenSuccess")
void givenValidMember_whenCreateToken_thenSuccess() {
// Given
MemberEntity member = createTestMemberEntity();
Set<SimpleGrantedAuthority> authorities = Collections.singleton(
new SimpleGrantedAuthority("ROLE_USER"));
// When
JwtTokenDTO tokens = jwtTokenProvider.createToken(member, authorities);
// Then
assertThat(tokens).isNotNull();
assertThat(tokens.getAccessToken()).isNotNull();
assertThat(tokens.getRefreshToken()).isNotNull();
assertThat(jwtTokenProvider.validateToken(tokens.getAccessToken())).isEqualTo(1);
}
/**
* 토큰 검증 테스트
* 유효한 토큰과 유효하지 않은 토큰에 대한 검증이 정상적으로 동작하는지 확인
*/
@Test
@DisplayName("givenToken_whenValidate_thenSuccess")
void givenToken_whenValidate_thenSuccess() {
// Given
String token = createValidToken();
// When & Then
assertThat(jwtTokenProvider.validateToken(token)).isEqualTo(1);
}
/**
* 인증 정보 추출 테스트
* JWT 토큰에서 인증 정보가 정상적으로 추출되는지 검증
*/
@Test
@DisplayName("givenValidToken_whenGetAuthentication_thenSuccess")
void givenValidToken_whenGetAuthentication_thenSuccess() {
// Given
String token = createValidToken();
// When
Authentication authentication = jwtTokenProvider.getAuthentication(token);
// Then
assertThat(authentication).isNotNull();
assertThat(authentication.isAuthenticated()).isTrue();
assertThat(authentication.getAuthorities()).hasSize(1);
}
/**
* 토큰 추출 테스트
* HTTP 요청 헤더에서 토큰이 정상적으로 추출되는지 검증
*/
@Test
@DisplayName("givenRequest_whenResolveToken_thenSuccess")
void givenRequest_whenResolveToken_thenSuccess() {
// Given
HttpServletRequest request = mock(HttpServletRequest.class);
String token = "test-token";
when(request.getHeader("Authorization")).thenReturn("Bearer " + token);
// When
String resolvedToken = jwtTokenProvider.resolveToken(request);
// Then
assertThat(resolvedToken).isEqualTo(token);
}
/**
* 유효하지 않은 토큰 검증 테스트
* 잘못된 형식의 토큰에 대해 적절한 예외가 발생하는지 검증
*/
@Test
@DisplayName("givenInvalidToken_whenValidate_thenThrowException")
void givenInvalidToken_whenValidate_thenThrowException() {
// Given
String invalidToken = "invalid-token";
// When & Then
assertThrows(InfraException.class, () -> jwtTokenProvider.validateToken(invalidToken));
}
// 테스트 헬퍼 메서드
private MemberEntity createTestMemberEntity() {
Set<String> roles = new HashSet<>();
roles.add("USER");
return MemberEntity.builder()
.userId("testUser")
.userName("Test User")
.password("password")
.roles(roles)
.build();
}
private String createValidToken() {
Algorithm algorithm = Algorithm.HMAC512(SECRET_KEY);
return JWT.create()
.withSubject("testUser")
.withClaim("auth", Collections.singletonList("ROLE_USER"))
.sign(algorithm);
}
}
@@ -0,0 +1,141 @@
package com.unicorn.lifesub.member.test.unit.domain;
import com.unicorn.lifesub.member.domain.Member;
import com.unicorn.lifesub.member.repository.entity.MemberEntity;
import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.Test;
import java.util.HashSet;
import java.util.Set;
import static org.assertj.core.api.Assertions.assertThat;
/**
* Member 도메인 객체 테스트 클래스
* 도메인 객체의 생성 및 엔티티 변환 로직을 검증
*/
class MemberTest {
// 테스트용 상수 정의
private static final String TEST_USER_ID = "testUser";
private static final String TEST_USER_NAME = "Test User";
private static final String TEST_PASSWORD = "testPassword";
/**
* Member 객체 생성 테스트
* Builder 패턴을 사용한 Member 객체 생성이 정상적으로 동작하는지 검증
*/
@Test
@DisplayName("givenMemberInfo_whenBuildMember_thenSuccess")
void givenMemberInfo_whenBuildMember_thenSuccess() {
// Given
Set<String> roles = new HashSet<>();
roles.add("USER");
// When
Member member = Member.builder()
.userId(TEST_USER_ID)
.userName(TEST_USER_NAME)
.password(TEST_PASSWORD)
.roles(roles)
.build();
// Then
assertThat(member).isNotNull();
assertThat(member.getUserId()).isEqualTo(TEST_USER_ID);
assertThat(member.getUserName()).isEqualTo(TEST_USER_NAME);
assertThat(member.getPassword()).isEqualTo(TEST_PASSWORD);
assertThat(member.getRoles()).containsExactly("USER");
}
/**
* Entity에서 Domain 객체로의 변환 테스트
* MemberEntity.toDomain() 메서드가 정상적으로 동작하는지 검증
*/
@Test
@DisplayName("givenMemberEntity_whenConvertToDomain_thenSuccess")
void givenMemberEntity_whenConvertToDomain_thenSuccess() {
// Given
MemberEntity entity = createTestMemberEntity();
// When
Member member = entity.toDomain();
// Then
assertThat(member).isNotNull();
assertThat(member.getUserId()).isEqualTo(TEST_USER_ID);
assertThat(member.getUserName()).isEqualTo(TEST_USER_NAME);
assertThat(member.getPassword()).isEqualTo(TEST_PASSWORD);
assertThat(member.getRoles()).containsExactly("USER");
}
/**
* Domain 객체에서 Entity로의 변환 테스트
* MemberEntity.fromDomain() 메서드가 정상적으로 동작하는지 검증
*/
@Test
@DisplayName("givenMemberDomain_whenConvertToEntity_thenSuccess")
void givenMemberDomain_whenConvertToEntity_thenSuccess() {
// Given
Member member = createTestMember();
// When
MemberEntity entity = MemberEntity.fromDomain(member);
// Then
assertThat(entity).isNotNull();
assertThat(entity.getUserId()).isEqualTo(TEST_USER_ID);
assertThat(entity.getUserName()).isEqualTo(TEST_USER_NAME);
assertThat(entity.getPassword()).isEqualTo(TEST_PASSWORD);
assertThat(entity.getRoles()).containsExactly("USER");
}
/**
* 다중 역할을 가진 Member 객체 생성 테스트
* 여러 역할을 가진 Member 객체가 정상적으로 생성되는지 검증
*/
@Test
@DisplayName("givenMultipleRoles_whenBuildMember_thenSuccess")
void givenMultipleRoles_whenBuildMember_thenSuccess() {
// Given
Set<String> roles = new HashSet<>();
roles.add("USER");
roles.add("ADMIN");
// When
Member member = Member.builder()
.userId(TEST_USER_ID)
.userName(TEST_USER_NAME)
.password(TEST_PASSWORD)
.roles(roles)
.build();
// Then
assertThat(member).isNotNull();
assertThat(member.getRoles()).hasSize(2);
assertThat(member.getRoles()).containsExactlyInAnyOrder("USER", "ADMIN");
}
// 테스트 헬퍼 메서드
private MemberEntity createTestMemberEntity() {
Set<String> roles = new HashSet<>();
roles.add("USER");
return MemberEntity.builder()
.userId(TEST_USER_ID)
.userName(TEST_USER_NAME)
.password(TEST_PASSWORD)
.roles(roles)
.build();
}
private Member createTestMember() {
Set<String> roles = new HashSet<>();
roles.add("USER");
return Member.builder()
.userId(TEST_USER_ID)
.userName(TEST_USER_NAME)
.password(TEST_PASSWORD)
.roles(roles)
.build();
}
}
@@ -0,0 +1,163 @@
package com.unicorn.lifesub.member.test.unit.service;
import com.unicorn.lifesub.common.dto.JwtTokenDTO;
import com.unicorn.lifesub.common.exception.BusinessException;
import com.unicorn.lifesub.common.exception.ErrorCode;
import com.unicorn.lifesub.common.exception.InfraException;
import com.unicorn.lifesub.member.config.jwt.JwtTokenProvider;
import com.unicorn.lifesub.member.dto.LoginRequest;
import com.unicorn.lifesub.member.dto.LogoutRequest;
import com.unicorn.lifesub.member.repository.entity.MemberEntity;
import com.unicorn.lifesub.member.repository.jpa.MemberRepository;
import com.unicorn.lifesub.member.service.MemberServiceImpl;
import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
import org.mockito.InjectMocks;
import org.mockito.Mock;
import org.mockito.junit.jupiter.MockitoExtension;
import org.springframework.security.crypto.password.PasswordEncoder;
import java.util.HashSet;
import java.util.Optional;
import java.util.Set;
import static org.assertj.core.api.Assertions.assertThat;
import static org.junit.jupiter.api.Assertions.assertThrows;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.BDDMockito.given;
import static org.mockito.Mockito.when;
/**
* 멤버 서비스 테스트 클래스
* 주요 비즈니스 로직인 로그인/로그아웃 기능을 검증
*/
@ExtendWith(MockitoExtension.class)
class MemberServiceImplTest {
@InjectMocks
private MemberServiceImpl memberService;
@Mock
private MemberRepository memberRepository;
@Mock
private PasswordEncoder passwordEncoder;
@Mock
private JwtTokenProvider jwtTokenProvider;
// 테스트용 상수 정의
private static final String TEST_USER_ID = "testUser";
private static final String TEST_PASSWORD = "testPassword";
private static final String TEST_USER_NAME = "Test User";
/**
* 로그인 성공 케이스 테스트
* 올바른 사용자 ID와 비밀번호로 로그인 시 JWT 토큰이 정상적으로 발급되는지 검증
*/
@Test
@DisplayName("givenValidCredentials_whenLogin_thenSuccess")
void givenValidCredentials_whenLogin_thenSuccess() {
// Given
LoginRequest request = new LoginRequest();
request.setUserId(TEST_USER_ID);
request.setPassword(TEST_PASSWORD);
MemberEntity memberEntity = createTestMemberEntity();
JwtTokenDTO expectedToken = createTestJwtTokenDTO();
given(memberRepository.findByUserId(TEST_USER_ID)).willReturn(Optional.of(memberEntity));
given(passwordEncoder.matches(TEST_PASSWORD, memberEntity.getPassword())).willReturn(true);
given(jwtTokenProvider.createToken(any(), any())).willReturn(expectedToken);
// When
JwtTokenDTO result = memberService.login(request);
// Then
assertThat(result).isNotNull();
assertThat(result.getAccessToken()).isEqualTo(expectedToken.getAccessToken());
assertThat(result.getRefreshToken()).isEqualTo(expectedToken.getRefreshToken());
}
/**
* 로그인 실패 케이스 테스트 - 사용자가 존재하지 않는 경우
* 존재하지 않는 사용자 ID로 로그인 시도 시 적절한 예외가 발생하는지 검증
*/
@Test
@DisplayName("givenNonExistentUser_whenLogin_thenThrowException")
void givenNonExistentUser_whenLogin_thenThrowException() {
// Given
LoginRequest request = new LoginRequest();
request.setUserId("nonexistent");
request.setPassword(TEST_PASSWORD);
when(memberRepository.findByUserId("nonexistent")).thenReturn(Optional.empty());
// When & Then
InfraException exception = assertThrows(InfraException.class,
() -> memberService.login(request));
assertThat(exception.getErrorCode()).isEqualTo(ErrorCode.MEMBER_NOT_FOUND);
}
/**
* 로그인 실패 케이스 테스트 - 잘못된 비밀번호
* 올바른 사용자 ID와 잘못된 비밀번호로 로그인 시도 시 적절한 예외가 발생하는지 검증
*/
@Test
@DisplayName("givenInvalidPassword_whenLogin_thenThrowException")
void givenInvalidPassword_whenLogin_thenThrowException() {
// Given
LoginRequest request = new LoginRequest();
request.setUserId(TEST_USER_ID);
request.setPassword("wrongPassword");
MemberEntity memberEntity = createTestMemberEntity();
given(memberRepository.findByUserId(TEST_USER_ID)).willReturn(Optional.of(memberEntity));
given(passwordEncoder.matches("wrongPassword", memberEntity.getPassword())).willReturn(false);
// When & Then
BusinessException exception = assertThrows(BusinessException.class,
() -> memberService.login(request));
assertThat(exception.getErrorCode()).isEqualTo(ErrorCode.INVALID_CREDENTIALS);
}
/**
* 로그아웃 테스트
* 로그아웃 요청 시 정상적으로 처리되는지 검증
*/
@Test
@DisplayName("givenLogoutRequest_whenLogout_thenSuccess")
void givenLogoutRequest_whenLogout_thenSuccess() {
// Given
LogoutRequest request = new LogoutRequest();
request.setUserId(TEST_USER_ID);
// When
var response = memberService.logout(request);
// Then
assertThat(response).isNotNull();
assertThat(response.getMessage()).contains("로그아웃이 완료되었습니다");
}
// 테스트 헬퍼 메서드
private MemberEntity createTestMemberEntity() {
Set<String> roles = new HashSet<>();
roles.add("USER");
return MemberEntity.builder()
.userId(TEST_USER_ID)
.userName(TEST_USER_NAME)
.password(TEST_PASSWORD)
.roles(roles)
.build();
}
private JwtTokenDTO createTestJwtTokenDTO() {
return JwtTokenDTO.builder()
.accessToken("test-access-token")
.refreshToken("test-refresh-token")
.build();
}
}