mirror of
https://github.com/cna-bootcamp/lifesub.git
synced 2026-06-13 04:59:10 +00:00
add testcode
This commit is contained in:
@@ -0,0 +1,144 @@
|
||||
package com.unicorn.lifesub.member.test.e2e;
|
||||
|
||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
import com.unicorn.lifesub.common.dto.ApiResponse;
|
||||
import com.unicorn.lifesub.common.dto.JwtTokenDTO;
|
||||
import com.unicorn.lifesub.member.dto.LoginRequest;
|
||||
import com.unicorn.lifesub.member.dto.LogoutRequest;
|
||||
import com.unicorn.lifesub.member.repository.jpa.MemberRepository;
|
||||
import com.unicorn.lifesub.member.test.e2e.config.TestContainerConfig;
|
||||
import com.unicorn.lifesub.member.test.e2e.support.TestDataManager;
|
||||
import org.junit.jupiter.api.BeforeEach;
|
||||
import org.junit.jupiter.api.DisplayName;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.beans.factory.annotation.Value;
|
||||
import org.springframework.boot.test.context.SpringBootTest;
|
||||
import org.springframework.http.MediaType;
|
||||
import org.springframework.security.test.web.servlet.setup.SecurityMockMvcConfigurers;
|
||||
import org.springframework.test.context.ActiveProfiles;
|
||||
import org.springframework.test.web.reactive.server.WebTestClient;
|
||||
import org.springframework.test.web.servlet.client.MockMvcWebTestClient;
|
||||
import org.springframework.web.context.WebApplicationContext;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
|
||||
@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)
|
||||
@ActiveProfiles("e2e-test")
|
||||
class MemberE2ETest extends TestContainerConfig {
|
||||
|
||||
@Autowired
|
||||
private WebApplicationContext context;
|
||||
|
||||
@Autowired
|
||||
private ObjectMapper objectMapper;
|
||||
|
||||
@Autowired
|
||||
private TestDataManager testDataManager;
|
||||
|
||||
@Autowired
|
||||
private MemberRepository memberRepository;
|
||||
|
||||
private WebTestClient webClient;
|
||||
|
||||
@Value("${test.user.id}")
|
||||
private String TEST_USER_ID;
|
||||
|
||||
@Value("${test.user.password}")
|
||||
private String TEST_PASSWORD;
|
||||
|
||||
@BeforeEach
|
||||
void setUp() {
|
||||
webClient = MockMvcWebTestClient
|
||||
.bindToApplicationContext(context)
|
||||
.apply(SecurityMockMvcConfigurers.springSecurity())
|
||||
.configureClient()
|
||||
.build();
|
||||
|
||||
memberRepository.deleteAll();
|
||||
testDataManager.setupTestData();
|
||||
}
|
||||
|
||||
@Test
|
||||
@DisplayName("로그인 성공 시나리오")
|
||||
void givenValidCredentials_whenLogin_thenSuccess() {
|
||||
// Given
|
||||
LoginRequest loginRequest = createLoginRequest(TEST_USER_ID, TEST_PASSWORD);
|
||||
|
||||
// When & Then
|
||||
webClient.post().uri("/api/auth/login")
|
||||
.contentType(MediaType.APPLICATION_JSON)
|
||||
.bodyValue(loginRequest)
|
||||
.exchange()
|
||||
.expectStatus().isOk()
|
||||
.expectBody(ApiResponse.class)
|
||||
.value(response -> {
|
||||
assertThat(response.getStatus()).isEqualTo(200);
|
||||
|
||||
JwtTokenDTO jwtToken = objectMapper.convertValue(response.getData(), JwtTokenDTO.class);
|
||||
assertThat(jwtToken.getAccessToken()).isNotNull();
|
||||
assertThat(jwtToken.getRefreshToken()).isNotNull();
|
||||
});
|
||||
}
|
||||
|
||||
@Test
|
||||
@DisplayName("잘못된 비밀번호로 로그인 실패 시나리오")
|
||||
void givenInvalidPassword_whenLogin_thenFail() {
|
||||
// Given
|
||||
LoginRequest loginRequest = createLoginRequest(TEST_USER_ID, "wrongpassword");
|
||||
|
||||
// When & Then
|
||||
webClient.post().uri("/api/auth/login")
|
||||
.contentType(MediaType.APPLICATION_JSON)
|
||||
.bodyValue(loginRequest)
|
||||
.exchange()
|
||||
.expectStatus().isUnauthorized()
|
||||
.expectBody(ApiResponse.class)
|
||||
.value(response -> {
|
||||
assertThat(response.getStatus()).isEqualTo(210);
|
||||
assertThat(response.getMessage()).isEqualTo("Invalid credentials");
|
||||
});
|
||||
}
|
||||
|
||||
@Test
|
||||
@DisplayName("로그인 후 로그아웃 시나리오")
|
||||
void givenValidToken_whenLogout_thenSuccess() {
|
||||
// Given - 먼저 로그인
|
||||
LoginRequest loginRequest = createLoginRequest(TEST_USER_ID, TEST_PASSWORD);
|
||||
|
||||
ApiResponse loginResponse = webClient.post().uri("/api/auth/login")
|
||||
.contentType(MediaType.APPLICATION_JSON)
|
||||
.bodyValue(loginRequest)
|
||||
.exchange()
|
||||
.expectStatus().isOk()
|
||||
.expectBody(ApiResponse.class)
|
||||
.returnResult()
|
||||
.getResponseBody();
|
||||
|
||||
JwtTokenDTO tokenDTO = objectMapper.convertValue(loginResponse.getData(), JwtTokenDTO.class);
|
||||
|
||||
// When - 로그아웃
|
||||
LogoutRequest logoutRequest = new LogoutRequest();
|
||||
logoutRequest.setUserId(TEST_USER_ID);
|
||||
|
||||
// Then
|
||||
webClient.post().uri("/api/auth/logout")
|
||||
.contentType(MediaType.APPLICATION_JSON)
|
||||
.header("Authorization", "Bearer " + tokenDTO.getAccessToken())
|
||||
.bodyValue(logoutRequest)
|
||||
.exchange()
|
||||
.expectStatus().isOk()
|
||||
.expectBody(ApiResponse.class)
|
||||
.value(response -> {
|
||||
assertThat(response.getStatus()).isEqualTo(200);
|
||||
assertThat(response.getMessage()).contains("Success");
|
||||
});
|
||||
}
|
||||
|
||||
private LoginRequest createLoginRequest(String userId, String password) {
|
||||
LoginRequest request = new LoginRequest();
|
||||
request.setUserId(userId);
|
||||
request.setPassword(password);
|
||||
return request;
|
||||
}
|
||||
}
|
||||
+25
@@ -0,0 +1,25 @@
|
||||
// TestContainerConfig.java
|
||||
package com.unicorn.lifesub.member.test.e2e.config;
|
||||
|
||||
import org.springframework.test.context.DynamicPropertyRegistry;
|
||||
import org.springframework.test.context.DynamicPropertySource;
|
||||
import org.testcontainers.containers.PostgreSQLContainer;
|
||||
import org.testcontainers.junit.jupiter.Container;
|
||||
import org.testcontainers.junit.jupiter.Testcontainers;
|
||||
|
||||
@Testcontainers
|
||||
public class TestContainerConfig {
|
||||
@Container
|
||||
static PostgreSQLContainer<?> postgreSQLContainer = new PostgreSQLContainer<>("postgres:13.2-alpine")
|
||||
.withDatabaseName("testdb")
|
||||
.withUsername("test")
|
||||
.withPassword("test");
|
||||
|
||||
@DynamicPropertySource
|
||||
static void registerPgProperties(DynamicPropertyRegistry registry) {
|
||||
registry.add("spring.datasource.url", postgreSQLContainer::getJdbcUrl);
|
||||
registry.add("spring.datasource.username", postgreSQLContainer::getUsername);
|
||||
registry.add("spring.datasource.password", postgreSQLContainer::getPassword);
|
||||
registry.add("spring.jpa.hibernate.ddl-auto", () -> "create-drop");
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,68 @@
|
||||
// TestDataManager.java
|
||||
package com.unicorn.lifesub.member.test.e2e.support;
|
||||
|
||||
import com.unicorn.lifesub.member.repository.entity.MemberEntity;
|
||||
import com.unicorn.lifesub.member.repository.jpa.MemberRepository;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import org.springframework.beans.factory.annotation.Value;
|
||||
import org.springframework.security.crypto.password.PasswordEncoder;
|
||||
import org.springframework.stereotype.Component;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
|
||||
import java.util.HashSet;
|
||||
import java.util.Set;
|
||||
|
||||
@Component
|
||||
@RequiredArgsConstructor
|
||||
public class TestDataManager {
|
||||
private final MemberRepository memberRepository;
|
||||
private final PasswordEncoder passwordEncoder;
|
||||
|
||||
@Value("${test.user.id}")
|
||||
private String TEST_USER_ID;
|
||||
|
||||
@Value("${test.user.password}")
|
||||
private String TEST_PASSWORD;
|
||||
|
||||
@Value("${test.user.name}")
|
||||
private String TEST_USER_NAME;
|
||||
|
||||
@Transactional
|
||||
public void setupTestData() {
|
||||
if (memberRepository.count() == 0) {
|
||||
// 기본 테스트 사용자 생성
|
||||
createTestUser();
|
||||
// 추가 테스트 데이터 생성
|
||||
createAdditionalTestData();
|
||||
}
|
||||
}
|
||||
|
||||
private void createTestUser() {
|
||||
Set<String> userRoles = new HashSet<>();
|
||||
userRoles.add("USER");
|
||||
|
||||
MemberEntity testUser = MemberEntity.builder()
|
||||
.userId(TEST_USER_ID)
|
||||
.userName(TEST_USER_NAME)
|
||||
.password(passwordEncoder.encode(TEST_PASSWORD)) // 암호화된 비밀번호 저장
|
||||
.roles(userRoles)
|
||||
.build();
|
||||
|
||||
memberRepository.save(testUser);
|
||||
}
|
||||
|
||||
private void createAdditionalTestData() {
|
||||
// 계정 잠금 테스트용 사용자
|
||||
Set<String> userRoles = new HashSet<>();
|
||||
userRoles.add("USER");
|
||||
|
||||
MemberEntity lockTestUser = MemberEntity.builder()
|
||||
.userId("locktest")
|
||||
.userName("Lock Test User")
|
||||
.password(passwordEncoder.encode("lockpass"))
|
||||
.roles(userRoles)
|
||||
.build();
|
||||
|
||||
memberRepository.save(lockTestUser);
|
||||
}
|
||||
}
|
||||
+23
@@ -0,0 +1,23 @@
|
||||
package com.unicorn.lifesub.member.test.integration.config;
|
||||
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.context.annotation.Profile;
|
||||
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
|
||||
import org.springframework.security.config.annotation.web.configurers.AbstractHttpConfigurer;
|
||||
import org.springframework.security.web.SecurityFilterChain;
|
||||
|
||||
@Configuration
|
||||
@Profile("integration-test")
|
||||
public class TestSecurityConfig {
|
||||
@Bean
|
||||
public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
|
||||
http
|
||||
.csrf(AbstractHttpConfigurer::disable)
|
||||
.authorizeHttpRequests(auth -> auth
|
||||
.requestMatchers("/api/auth/**").permitAll()
|
||||
.anyRequest().authenticated()
|
||||
);
|
||||
return http.build();
|
||||
}
|
||||
}
|
||||
+179
@@ -0,0 +1,179 @@
|
||||
package com.unicorn.lifesub.member.test.integration.controller;
|
||||
|
||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
import com.unicorn.lifesub.common.dto.JwtTokenDTO;
|
||||
import com.unicorn.lifesub.member.controller.MemberController;
|
||||
import com.unicorn.lifesub.member.dto.LoginRequest;
|
||||
import com.unicorn.lifesub.member.dto.LogoutRequest;
|
||||
import com.unicorn.lifesub.member.dto.LogoutResponse;
|
||||
import com.unicorn.lifesub.member.service.MemberService;
|
||||
import com.unicorn.lifesub.member.test.integration.config.TestSecurityConfig;
|
||||
import org.junit.jupiter.api.DisplayName;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.boot.test.autoconfigure.web.servlet.WebMvcTest;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.context.annotation.Import;
|
||||
import org.springframework.http.MediaType;
|
||||
import org.springframework.test.context.ActiveProfiles;
|
||||
import org.springframework.test.web.servlet.MockMvc;
|
||||
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
|
||||
|
||||
import static org.mockito.ArgumentMatchers.any;
|
||||
import static org.mockito.BDDMockito.given;
|
||||
import static org.mockito.Mockito.mock;
|
||||
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.post;
|
||||
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.jsonPath;
|
||||
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;
|
||||
|
||||
/**
|
||||
* MemberController 통합 테스트 클래스
|
||||
* 회원 인증 관련 API의 요청/응답을 검증합니다.
|
||||
*
|
||||
* @author Tera
|
||||
* @version 1.0
|
||||
*/
|
||||
@WebMvcTest(MemberController.class)
|
||||
@Import({MemberControllerIntegrationTest.TestConfig.class, TestSecurityConfig.class})
|
||||
@ActiveProfiles("integration-test")
|
||||
class MemberControllerIntegrationTest {
|
||||
@Autowired
|
||||
private MockMvc mockMvc;
|
||||
|
||||
@Autowired
|
||||
private ObjectMapper objectMapper;
|
||||
|
||||
@Autowired
|
||||
private MemberService memberService;
|
||||
|
||||
/**
|
||||
* 테스트를 위한 설정 클래스입니다.
|
||||
* Controller와 의존성들을 직접 등록하여 테스트 환경을 구성합니다.
|
||||
*
|
||||
* @implNote 1. Controller와 필요한 빈들을 직접 등록하여 의존성을 명확히 합니다.
|
||||
* 2. Service는 Mockito를 통해 mock 객체로 대체하여 테스트를 격리합니다.
|
||||
*/
|
||||
@Configuration
|
||||
static class TestConfig implements WebMvcConfigurer {
|
||||
|
||||
/**
|
||||
* MemberController 빈을 등록합니다.
|
||||
* memberService()를 통해 Mock 객체를 주입받아 Controller를 생성합니다.
|
||||
*
|
||||
* @return MemberController 인스턴스
|
||||
*/
|
||||
@Bean
|
||||
public MemberController memberController() {
|
||||
return new MemberController(memberService());
|
||||
}
|
||||
|
||||
/**
|
||||
* MemberService Mock 객체를 생성하여 반환합니다.
|
||||
* 실제 Service 구현체 대신 Mock 객체를 사용하여 테스트를 격리합니다.
|
||||
*
|
||||
* @return MemberService Mock 객체
|
||||
*/
|
||||
@Bean
|
||||
public MemberService memberService() {
|
||||
return mock(MemberService.class);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 로그인 성공 케이스를 테스트합니다.
|
||||
* 올바른 사용자 ID와 비밀번호로 요청 시 JWT 토큰이 정상적으로 발급되는지 검증합니다.
|
||||
*
|
||||
* @throws Exception MockMvc 수행 중 발생할 수 있는 예외
|
||||
*/
|
||||
@Test
|
||||
@DisplayName("로그인 성공 테스트")
|
||||
void loginSuccess() throws Exception {
|
||||
// Given: 테스트에 필요한 요청 데이터와 응답 객체를 준비
|
||||
LoginRequest request = new LoginRequest();
|
||||
request.setUserId("testUser");
|
||||
request.setPassword("testPass");
|
||||
|
||||
JwtTokenDTO tokenDTO = JwtTokenDTO.builder()
|
||||
.accessToken("test-access-token")
|
||||
.refreshToken("test-refresh-token")
|
||||
.build();
|
||||
|
||||
given(memberService.login(any(LoginRequest.class))).willReturn(tokenDTO);
|
||||
|
||||
// When & Then: API 호출 결과 검증
|
||||
mockMvc.perform(post("/api/auth/login")
|
||||
.contentType(MediaType.APPLICATION_JSON)
|
||||
.content(objectMapper.writeValueAsString(request)))
|
||||
.andExpect(status().isOk())
|
||||
.andExpect(jsonPath("$.status").value(200))
|
||||
.andExpect(jsonPath("$.data.accessToken").value("test-access-token"))
|
||||
.andExpect(jsonPath("$.data.refreshToken").value("test-refresh-token"));
|
||||
}
|
||||
|
||||
/**
|
||||
* 로그인 실패 케이스를 테스트합니다.
|
||||
* 잘못된 형식의 요청 데이터로 API 호출 시 적절한 에러 응답이 반환되는지 검증합니다.
|
||||
*
|
||||
* @throws Exception MockMvc 수행 중 발생할 수 있는 예외
|
||||
*/
|
||||
@Test
|
||||
@DisplayName("로그인 실패 테스트 - 잘못된 요청 형식")
|
||||
void loginFailInvalidRequest() throws Exception {
|
||||
// Given: 검증에 실패하도록 필수 필드가 비어있는 요청 객체 생성
|
||||
LoginRequest request = new LoginRequest();
|
||||
|
||||
// When & Then: API 호출 결과 검증
|
||||
mockMvc.perform(post("/api/auth/login")
|
||||
.contentType(MediaType.APPLICATION_JSON)
|
||||
.content(objectMapper.writeValueAsString(request)))
|
||||
.andExpect(status().isBadRequest());
|
||||
}
|
||||
|
||||
/**
|
||||
* 로그아웃 성공 케이스를 테스트합니다.
|
||||
* 정상적인 로그아웃 요청 시 성공 응답이 반환되는지 검증합니다.
|
||||
*
|
||||
* @throws Exception MockMvc 수행 중 발생할 수 있는 예외
|
||||
*/
|
||||
@Test
|
||||
@DisplayName("로그아웃 성공 테스트")
|
||||
void logoutSuccess() throws Exception {
|
||||
// Given: 테스트에 필요한 요청 데이터와 응답 객체를 준비
|
||||
LogoutRequest request = new LogoutRequest();
|
||||
request.setUserId("testUser");
|
||||
|
||||
LogoutResponse response = LogoutResponse.builder()
|
||||
.message("로그아웃이 완료되었습니다.")
|
||||
.build();
|
||||
|
||||
given(memberService.logout(any(LogoutRequest.class))).willReturn(response);
|
||||
|
||||
// When & Then: API 호출 결과 검증
|
||||
mockMvc.perform(post("/api/auth/logout")
|
||||
.contentType(MediaType.APPLICATION_JSON)
|
||||
.content(objectMapper.writeValueAsString(request)))
|
||||
.andExpect(status().isOk())
|
||||
.andExpect(jsonPath("$.status").value(200))
|
||||
.andExpect(jsonPath("$.data.message").value("로그아웃이 완료되었습니다."));
|
||||
}
|
||||
|
||||
/**
|
||||
* 로그아웃 실패 케이스를 테스트합니다.
|
||||
* 잘못된 형식의 요청 데이터로 API 호출 시 적절한 에러 응답이 반환되는지 검증합니다.
|
||||
*
|
||||
* @throws Exception MockMvc 수행 중 발생할 수 있는 예외
|
||||
*/
|
||||
@Test
|
||||
@DisplayName("로그아웃 실패 테스트 - 잘못된 요청 형식")
|
||||
void logoutFailInvalidRequest() throws Exception {
|
||||
// Given: 검증에 실패하도록 필수 필드가 비어있는 요청 객체 생성
|
||||
LogoutRequest request = new LogoutRequest();
|
||||
|
||||
// When & Then: API 호출 결과 검증
|
||||
mockMvc.perform(post("/api/auth/logout")
|
||||
.contentType(MediaType.APPLICATION_JSON)
|
||||
.content(objectMapper.writeValueAsString(request)))
|
||||
.andExpect(status().isBadRequest());
|
||||
}
|
||||
}
|
||||
+149
@@ -0,0 +1,149 @@
|
||||
package com.unicorn.lifesub.member.test.integration.repository;
|
||||
|
||||
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.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.boot.test.autoconfigure.jdbc.AutoConfigureTestDatabase;
|
||||
import org.springframework.boot.test.autoconfigure.orm.jpa.DataJpaTest;
|
||||
import org.springframework.boot.test.autoconfigure.orm.jpa.TestEntityManager;
|
||||
import org.springframework.test.context.ActiveProfiles;
|
||||
import org.springframework.test.context.DynamicPropertyRegistry;
|
||||
import org.springframework.test.context.DynamicPropertySource;
|
||||
import org.testcontainers.containers.PostgreSQLContainer;
|
||||
import org.testcontainers.junit.jupiter.Container;
|
||||
import org.testcontainers.junit.jupiter.Testcontainers;
|
||||
|
||||
import java.util.HashSet;
|
||||
import java.util.Optional;
|
||||
import java.util.Set;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
|
||||
/**
|
||||
* MemberRepository 통합 테스트
|
||||
* TestContainers를 사용하여 실제 PostgreSQL DB와의 상호작용을 테스트합니다.
|
||||
*/
|
||||
@DataJpaTest
|
||||
@AutoConfigureTestDatabase(replace = AutoConfigureTestDatabase.Replace.NONE)
|
||||
@Testcontainers
|
||||
@ActiveProfiles("integration-test")
|
||||
class MemberRepositoryIntegrationTest {
|
||||
@Container
|
||||
static PostgreSQLContainer<?> postgreSQLContainer = new PostgreSQLContainer<>("postgres:13.2-alpine")
|
||||
.withDatabaseName("member")
|
||||
.withUsername("test")
|
||||
.withPassword("test");
|
||||
|
||||
@DynamicPropertySource
|
||||
static void registerPgProperties(DynamicPropertyRegistry registry) {
|
||||
registry.add("spring.datasource.url", postgreSQLContainer::getJdbcUrl);
|
||||
registry.add("spring.datasource.username", postgreSQLContainer::getUsername);
|
||||
registry.add("spring.datasource.password", postgreSQLContainer::getPassword);
|
||||
}
|
||||
|
||||
@Autowired
|
||||
private MemberRepository memberRepository;
|
||||
|
||||
@Autowired
|
||||
private TestEntityManager entityManager;
|
||||
|
||||
@Test
|
||||
@DisplayName("회원 저장 및 조회 테스트")
|
||||
void givenMemberEntity_whenSave_thenFindByUserId() {
|
||||
// Given
|
||||
String userId = "testUser";
|
||||
Set<String> roles = new HashSet<>();
|
||||
roles.add("USER");
|
||||
|
||||
MemberEntity member = MemberEntity.builder()
|
||||
.userId(userId)
|
||||
.userName("Test User")
|
||||
.password("encodedPassword")
|
||||
.roles(roles)
|
||||
.build();
|
||||
|
||||
// When
|
||||
entityManager.persistAndFlush(member);
|
||||
entityManager.clear(); // 1차 캐시 클리어
|
||||
|
||||
// Then
|
||||
Optional<MemberEntity> foundMember = memberRepository.findByUserId(userId);
|
||||
assertThat(foundMember).isPresent();
|
||||
assertThat(foundMember.get().getUserId()).isEqualTo(userId);
|
||||
assertThat(foundMember.get().getUserName()).isEqualTo("Test User");
|
||||
assertThat(foundMember.get().getRoles()).containsExactly("USER");
|
||||
}
|
||||
|
||||
@Test
|
||||
@DisplayName("존재하지 않는 회원 조회 테스트")
|
||||
void givenNonExistentUserId_whenFindByUserId_thenReturnEmpty() {
|
||||
// Given
|
||||
String nonExistentUserId = "nonexistent";
|
||||
|
||||
// When
|
||||
Optional<MemberEntity> result = memberRepository.findByUserId(nonExistentUserId);
|
||||
|
||||
// Then
|
||||
assertThat(result).isEmpty();
|
||||
}
|
||||
|
||||
@Test
|
||||
@DisplayName("회원 정보 업데이트 테스트")
|
||||
void givenExistingMember_whenUpdateInfo_thenSuccess() {
|
||||
// Given
|
||||
String userId = "testUser";
|
||||
Set<String> roles = new HashSet<>();
|
||||
roles.add("USER");
|
||||
|
||||
MemberEntity member = MemberEntity.builder()
|
||||
.userId(userId)
|
||||
.userName("Original Name")
|
||||
.password("originalPassword")
|
||||
.roles(roles)
|
||||
.build();
|
||||
|
||||
entityManager.persistAndFlush(member);
|
||||
entityManager.clear();
|
||||
|
||||
// When
|
||||
MemberEntity foundMember = memberRepository.findByUserId(userId).get();
|
||||
foundMember.updateUserName("Updated Name");
|
||||
entityManager.persistAndFlush(foundMember);
|
||||
entityManager.clear();
|
||||
|
||||
// Then
|
||||
MemberEntity updatedMember = memberRepository.findByUserId(userId).get();
|
||||
assertThat(updatedMember.getUserName()).isEqualTo("Updated Name");
|
||||
}
|
||||
|
||||
@Test
|
||||
@DisplayName("회원 삭제 테스트")
|
||||
void givenExistingMember_whenDelete_thenCannotFind() {
|
||||
// Given
|
||||
String userId = "testUser";
|
||||
Set<String> roles = new HashSet<>();
|
||||
roles.add("USER");
|
||||
|
||||
MemberEntity member = MemberEntity.builder()
|
||||
.userId(userId)
|
||||
.userName("Test User")
|
||||
.password("password")
|
||||
.roles(roles)
|
||||
.build();
|
||||
|
||||
entityManager.persistAndFlush(member);
|
||||
entityManager.clear();
|
||||
|
||||
// When
|
||||
MemberEntity foundMember = memberRepository.findByUserId(userId).get();
|
||||
memberRepository.delete(foundMember);
|
||||
entityManager.flush();
|
||||
entityManager.clear();
|
||||
|
||||
// Then
|
||||
Optional<MemberEntity> deletedMember = memberRepository.findByUserId(userId);
|
||||
assertThat(deletedMember).isEmpty();
|
||||
}
|
||||
}
|
||||
+87
@@ -0,0 +1,87 @@
|
||||
package com.unicorn.lifesub.member.test.integration.service;
|
||||
|
||||
import com.unicorn.lifesub.common.dto.JwtTokenDTO;
|
||||
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.dto.LogoutResponse;
|
||||
import com.unicorn.lifesub.member.repository.entity.MemberEntity;
|
||||
import com.unicorn.lifesub.member.repository.jpa.MemberRepository;
|
||||
import com.unicorn.lifesub.member.service.MemberServiceImpl;
|
||||
import com.unicorn.lifesub.member.test.integration.config.TestSecurityConfig;
|
||||
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.context.annotation.Import;
|
||||
import org.springframework.security.crypto.password.PasswordEncoder;
|
||||
import org.springframework.test.context.ActiveProfiles;
|
||||
|
||||
import java.util.Optional;
|
||||
|
||||
import static com.unicorn.lifesub.member.test.integration.support.TestDataFactory.*;
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
import static org.mockito.ArgumentMatchers.any;
|
||||
import static org.mockito.ArgumentMatchers.eq;
|
||||
import static org.mockito.BDDMockito.given;
|
||||
import static org.mockito.Mockito.verify;
|
||||
|
||||
@ExtendWith(MockitoExtension.class)
|
||||
@Import(TestSecurityConfig.class)
|
||||
@ActiveProfiles("integration-test")
|
||||
class MemberServiceIntegrationTest {
|
||||
|
||||
@Mock
|
||||
private MemberRepository memberRepository;
|
||||
|
||||
@Mock
|
||||
private PasswordEncoder passwordEncoder;
|
||||
|
||||
@Mock
|
||||
private JwtTokenProvider jwtTokenProvider;
|
||||
|
||||
@InjectMocks
|
||||
private MemberServiceImpl memberService;
|
||||
|
||||
@Test
|
||||
@DisplayName("유효한 자격증명으로 로그인 성공")
|
||||
void givenValidCredentials_whenLogin_thenReturnJwtToken() {
|
||||
// Given
|
||||
LoginRequest loginRequest = createLoginRequest();
|
||||
MemberEntity memberEntity = createMemberEntity();
|
||||
|
||||
given(memberRepository.findByUserId(TEST_USER_ID)).willReturn(Optional.of(memberEntity));
|
||||
given(passwordEncoder.matches(TEST_PASSWORD, memberEntity.getPassword())).willReturn(true);
|
||||
given(jwtTokenProvider.createToken(eq(memberEntity), any())).willReturn(
|
||||
new JwtTokenDTO("accessToken", "refreshToken"));
|
||||
|
||||
// When
|
||||
JwtTokenDTO result = memberService.login(loginRequest);
|
||||
|
||||
// Then
|
||||
assertThat(result).isNotNull();
|
||||
assertThat(result.getAccessToken()).isEqualTo("accessToken");
|
||||
assertThat(result.getRefreshToken()).isEqualTo("refreshToken");
|
||||
|
||||
verify(memberRepository).findByUserId(TEST_USER_ID);
|
||||
verify(passwordEncoder).matches(TEST_PASSWORD, memberEntity.getPassword());
|
||||
verify(jwtTokenProvider).createToken(eq(memberEntity), any());
|
||||
}
|
||||
|
||||
@Test
|
||||
@DisplayName("로그아웃 처리 성공")
|
||||
void givenUserId_whenLogout_thenSuccess() {
|
||||
// Given
|
||||
LogoutRequest request = new LogoutRequest();
|
||||
request.setUserId(TEST_USER_ID);
|
||||
|
||||
// When
|
||||
LogoutResponse response = memberService.logout(request);
|
||||
|
||||
// Then
|
||||
assertThat(response).isNotNull();
|
||||
assertThat(response.getMessage()).contains("로그아웃");
|
||||
}
|
||||
}
|
||||
+32
@@ -0,0 +1,32 @@
|
||||
package com.unicorn.lifesub.member.test.integration.support;
|
||||
|
||||
import com.unicorn.lifesub.member.repository.entity.MemberEntity;
|
||||
import com.unicorn.lifesub.member.dto.LoginRequest;
|
||||
|
||||
import java.util.HashSet;
|
||||
import java.util.Set;
|
||||
|
||||
public class TestDataFactory {
|
||||
public static final String TEST_USER_ID = "testUser";
|
||||
public static final String TEST_PASSWORD = "Password123!";
|
||||
public static final String TEST_USERNAME = "Test User";
|
||||
|
||||
public static MemberEntity createMemberEntity() {
|
||||
Set<String> roles = new HashSet<>();
|
||||
roles.add("ROLE_USER");
|
||||
|
||||
return MemberEntity.builder()
|
||||
.userId(TEST_USER_ID)
|
||||
.userName(TEST_USERNAME)
|
||||
.password(TEST_PASSWORD)
|
||||
.roles(roles)
|
||||
.build();
|
||||
}
|
||||
|
||||
public static LoginRequest createLoginRequest() {
|
||||
LoginRequest request = new LoginRequest();
|
||||
request.setUserId(TEST_USER_ID);
|
||||
request.setPassword(TEST_PASSWORD);
|
||||
return request;
|
||||
}
|
||||
}
|
||||
+1
-1
@@ -25,7 +25,7 @@ import static org.mockito.BDDMockito.given;
|
||||
* Spring Security의 UserDetailsService 구현체 검증
|
||||
*/
|
||||
@ExtendWith(MockitoExtension.class)
|
||||
class CustomUserDetailsServiceTest {
|
||||
class CustomUserDetailsServiceUnitTest {
|
||||
|
||||
@InjectMocks
|
||||
private CustomUserDetailsService userDetailsService;
|
||||
+1
-1
@@ -26,7 +26,7 @@ import static org.mockito.Mockito.when;
|
||||
* JWT 토큰 제공자 테스트 클래스
|
||||
* 토큰 생성, 검증, 파싱 등의 기능을 검증
|
||||
*/
|
||||
class JwtTokenProviderTest {
|
||||
class JwtTokenProviderUnitTest {
|
||||
|
||||
private JwtTokenProvider jwtTokenProvider;
|
||||
private static final String SECRET_KEY = "test-secret-key";
|
||||
+1
-1
@@ -14,7 +14,7 @@ import static org.assertj.core.api.Assertions.assertThat;
|
||||
* Member 도메인 객체 테스트 클래스
|
||||
* 도메인 객체의 생성 및 엔티티 변환 로직을 검증
|
||||
*/
|
||||
class MemberTest {
|
||||
class MemberUnitTest {
|
||||
|
||||
// 테스트용 상수 정의
|
||||
private static final String TEST_USER_ID = "testUser";
|
||||
+1
-1
@@ -33,7 +33,7 @@ import static org.mockito.Mockito.when;
|
||||
* 주요 비즈니스 로직인 로그인/로그아웃 기능을 검증
|
||||
*/
|
||||
@ExtendWith(MockitoExtension.class)
|
||||
class MemberServiceImplTest {
|
||||
class MemberServiceImplUnitTest {
|
||||
|
||||
@InjectMocks
|
||||
private MemberServiceImpl memberService;
|
||||
@@ -0,0 +1,35 @@
|
||||
# src/test/resources/application-e2e-test.yml
|
||||
|
||||
spring:
|
||||
application:
|
||||
name: member-service-test
|
||||
jpa:
|
||||
hibernate:
|
||||
ddl-auto: create-drop
|
||||
show-sql: true
|
||||
properties:
|
||||
hibernate:
|
||||
format_sql: true
|
||||
dialect: org.hibernate.dialect.PostgreSQLDialect
|
||||
|
||||
# JWT 설정
|
||||
jwt:
|
||||
secret-key: testSecretKeyForE2ETestingPurposesOnlyDoNotUseInProduction
|
||||
access-token-validity: 3600000 # 1시간
|
||||
refresh-token-validity: 86400000 # 24시간
|
||||
|
||||
allowed-origins: http://localhost:3000
|
||||
|
||||
# 로깅 설정
|
||||
logging:
|
||||
level:
|
||||
com.unicorn: DEBUG
|
||||
org.hibernate.SQL: DEBUG
|
||||
org.hibernate.type.descriptor.sql.BasicBinder: TRACE
|
||||
|
||||
# 테스트용 사용자 설정
|
||||
test:
|
||||
user:
|
||||
id: testuser
|
||||
password: Test1234!
|
||||
name: Test User
|
||||
Reference in New Issue
Block a user