Skip to content

Commit 46d71fd

Browse files
Merge pull request #206 from prgrms-web-devcourse-final-project/feat/#195
[User] 유저 도메인 테스트 코드 작성
2 parents cf3da3c + 7720a63 commit 46d71fd

7 files changed

Lines changed: 467 additions & 16 deletions

File tree

src/main/java/com/back/web7_9_codecrete_be/domain/users/dto/request/UserUpdateNicknameRequest.java

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,9 +2,13 @@
22

33
import jakarta.validation.constraints.NotBlank;
44
import jakarta.validation.constraints.Size;
5+
import lombok.AllArgsConstructor;
56
import lombok.Getter;
7+
import lombok.NoArgsConstructor;
68

79
@Getter
10+
@NoArgsConstructor
11+
@AllArgsConstructor
812
public class UserUpdateNicknameRequest {
913

1014
@NotBlank(message = "닉네임은 필수입니다.")

src/main/java/com/back/web7_9_codecrete_be/global/error/code/UserErrorCode.java

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -8,16 +8,16 @@
88
@AllArgsConstructor
99
public enum UserErrorCode implements ErrorCode {
1010

11-
// 1xx - User 상태 / 중복
11+
// 10x - User 상태 / 중복
1212
NICKNAME_DUPLICATED(HttpStatus.CONFLICT, "U-100", "이미 사용 중인 닉네임입니다."),
1313
USER_DELETED(HttpStatus.FORBIDDEN, "U-101", "탈퇴한 사용자입니다."),
1414
USER_NOT_FOUND(HttpStatus.NOT_FOUND, "U-102", "사용자를 찾을 수 없습니다."),
1515
USER_RESTORE_EXPIRED(HttpStatus.BAD_REQUEST, "U-103", "계정 복구 가능 기간이 만료되었습니다."),
1616
USER_NOT_DELETED(HttpStatus.BAD_REQUEST, "U-104", "탈퇴 상태의 계정만 복구할 수 있습니다."),
1717
INVALID_RESTORE_TOKEN(HttpStatus.BAD_REQUEST, "U-105", "유효하지 않거나 만료된 복구 링크입니다."),
1818

19-
// 2xx - 인증 / 비밀번호
20-
INVALID_PASSWORD(HttpStatus.BAD_REQUEST, "U-120", "현재 비밀번호가 일치하지 않습니다.");
19+
// 11x - 비밀번호
20+
INVALID_PASSWORD(HttpStatus.BAD_REQUEST, "U-110", "현재 비밀번호가 일치하지 않습니다.");
2121

2222
private final HttpStatus status;
2323
private final String code;
Lines changed: 47 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,57 @@
11
spring:
2+
datasource:
3+
url: jdbc:h2:mem:testdb;MODE=MySQL;DB_CLOSE_DELAY=-1
4+
driver-class-name: org.h2.Driver
5+
username: sa
6+
password:
7+
jpa:
8+
hibernate:
9+
ddl-auto: create-drop
10+
show-sql: true
211
data:
312
redis:
413
host: localhost
514
port: 6379
615

16+
spotify:
17+
client-id: test-id
18+
client-secret: test-secret
19+
20+
jwt:
21+
secret: c2VjcmV0LWtleS1mb3ItdGVzdGluZy1wdXJwb3Nlcy1vbmx5LW5vdC1mb3ItcHJvZHVjdGlvbg==
22+
access-token-expiration: 3600
23+
refresh-token-expiration: 3600
24+
25+
mailgun:
26+
api-key: test
27+
domain: test
28+
from: test@test.com
29+
30+
tmap:
31+
api-key: test
32+
kakao:
33+
restapi-key: test
34+
kopis:
35+
api-key: test
36+
37+
oauth:
38+
kakao:
39+
client-id: test
40+
client-secret: test
41+
redirect-uri: test
42+
google:
43+
client-id: test
44+
client-secret: test
45+
redirect-uri: test
46+
747
cloud:
848
aws:
949
s3:
1050
bucket: test-bucket
11-
Credentials:
12-
accessKey: test
13-
secretKey: test
51+
credentials:
52+
access-key: test
53+
secret-key: test
54+
region:
55+
static: ap-northeast-2
56+
stack:
57+
auto: false
Lines changed: 231 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,231 @@
1+
package com.back.web7_9_codecrete_be.domain.users.controller;
2+
3+
import com.back.web7_9_codecrete_be.domain.auth.service.TokenService;
4+
import com.back.web7_9_codecrete_be.domain.users.dto.response.UserResponse;
5+
import com.back.web7_9_codecrete_be.domain.users.entity.User;
6+
import com.back.web7_9_codecrete_be.domain.users.service.UserService;
7+
import com.back.web7_9_codecrete_be.global.error.code.UserErrorCode;
8+
import com.back.web7_9_codecrete_be.global.error.exception.BusinessException;
9+
import com.back.web7_9_codecrete_be.global.rq.Rq;
10+
import com.fasterxml.jackson.databind.ObjectMapper;
11+
import org.junit.jupiter.api.BeforeEach;
12+
import org.junit.jupiter.api.DisplayName;
13+
import org.junit.jupiter.api.Test;
14+
import org.springframework.beans.factory.annotation.Autowired;
15+
import org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureMockMvc;
16+
import org.springframework.boot.test.context.SpringBootTest;
17+
import org.springframework.boot.test.mock.mockito.MockBean;
18+
import org.springframework.http.MediaType;
19+
import org.springframework.mock.web.MockMultipartFile;
20+
import org.springframework.security.test.context.support.WithMockUser;
21+
import org.springframework.test.context.ActiveProfiles;
22+
import org.springframework.test.web.servlet.MockMvc;
23+
import org.springframework.transaction.annotation.Transactional;
24+
25+
import static org.mockito.ArgumentMatchers.any;
26+
import static org.mockito.BDDMockito.given;
27+
import static org.mockito.Mockito.*;
28+
import static org.springframework.security.test.web.servlet.request.SecurityMockMvcRequestPostProcessors.csrf;
29+
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.*;
30+
import static org.springframework.test.web.servlet.result.MockMvcResultHandlers.print;
31+
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.jsonPath;
32+
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;
33+
34+
@SpringBootTest
35+
@AutoConfigureMockMvc
36+
@ActiveProfiles("test")
37+
@Transactional
38+
class UserControllerTest {
39+
40+
@Autowired
41+
private MockMvc mockMvc;
42+
43+
@Autowired
44+
private ObjectMapper objectMapper;
45+
46+
@MockBean
47+
private UserService userService;
48+
49+
@MockBean
50+
private TokenService tokenService;
51+
52+
@MockBean
53+
private Rq rq;
54+
55+
private User mockUser;
56+
private UserResponse mockUserResponse;
57+
58+
@BeforeEach
59+
void setUp() {
60+
mockUser = User.builder()
61+
.email("test@example.com")
62+
.nickname("testUser")
63+
.build();
64+
65+
mockUserResponse = UserResponse.builder()
66+
.email("test@example.com")
67+
.nickname("testUser")
68+
.profileImageUrl("https://example.com/profile.jpg")
69+
.build();
70+
71+
// Rq가 사용될 때 가짜 유저 반환 설정
72+
lenient().when(rq.getUser()).thenReturn(mockUser);
73+
}
74+
75+
// 성공 테스트 시나리오
76+
77+
@Test
78+
@WithMockUser
79+
@DisplayName("내 정보 조회 성공")
80+
void getMyInfo_Success() throws Exception {
81+
given(userService.getMyInfo(any())).willReturn(mockUserResponse);
82+
83+
mockMvc.perform(get("/api/v1/users/me"))
84+
.andDo(print())
85+
.andExpect(status().isOk())
86+
.andExpect(jsonPath("$.resultCode").value("OK"))
87+
.andExpect(jsonPath("$.msg").value("사용자 정보 조회 성공"))
88+
.andExpect(jsonPath("$.data.email").value("test@example.com"));
89+
}
90+
91+
@Test
92+
@WithMockUser
93+
@DisplayName("닉네임 수정 성공")
94+
void updateNickname_Success() throws Exception {
95+
String jsonRequest = "{\"nickname\": \"newNickname\"}";
96+
UserResponse updatedResponse = UserResponse.builder().nickname("newNickname").build();
97+
98+
given(userService.updateNickname(any(), any())).willReturn(updatedResponse);
99+
100+
mockMvc.perform(patch("/api/v1/users/nickname")
101+
.with(csrf())
102+
.contentType(MediaType.APPLICATION_JSON)
103+
.content(jsonRequest))
104+
.andExpect(status().isOk())
105+
.andExpect(jsonPath("$.resultCode").value("OK"))
106+
.andExpect(jsonPath("$.data.nickname").value("newNickname"));
107+
}
108+
109+
@Test
110+
@WithMockUser
111+
@DisplayName("프로필 이미지 수정 성공")
112+
void updateProfileImage_Success() throws Exception {
113+
MockMultipartFile file = new MockMultipartFile(
114+
"file", "profile.jpg", MediaType.IMAGE_JPEG_VALUE, "content".getBytes());
115+
116+
given(userService.updateProfileImage(any(), any())).willReturn("https://new-url.com");
117+
118+
mockMvc.perform(multipart("/api/v1/users/profile-image")
119+
.file(file)
120+
.with(csrf())
121+
.with(request -> {
122+
request.setMethod("PATCH");
123+
return request;
124+
}))
125+
.andExpect(status().isOk())
126+
.andExpect(jsonPath("$.msg").value("프로필 이미지가 변경되었습니다."));
127+
}
128+
129+
@Test
130+
@WithMockUser
131+
@DisplayName("비밀번호 변경 성공")
132+
void updatePassword_Success() throws Exception {
133+
134+
String jsonRequest = """
135+
136+
{
137+
138+
"currentPassword": "oldPassword1!",
139+
140+
"newPassword": "newPassword1!"
141+
142+
}
143+
144+
""";
145+
146+
mockMvc.perform(patch("/api/v1/users/password")
147+
148+
.with(csrf())
149+
150+
.contentType(MediaType.APPLICATION_JSON)
151+
152+
.content(jsonRequest))
153+
154+
.andExpect(status().isOk());
155+
156+
verify(userService).updatePassword(any(), any());
157+
158+
}
159+
160+
@Test
161+
@WithMockUser
162+
@DisplayName("회원 탈퇴 성공")
163+
void deleteMyAccount_Success() throws Exception {
164+
mockMvc.perform(delete("/api/v1/users/me")
165+
.with(csrf()))
166+
.andDo(print())
167+
.andExpect(status().isOk())
168+
.andExpect(jsonPath("$.resultCode").value("OK"))
169+
.andExpect(jsonPath("$.msg").value("정상적으로 처리되었습니다."))
170+
.andExpect(jsonPath("$.data").value("회원 탈퇴가 완료되었습니다."));
171+
}
172+
173+
// 실패 테스트 시나리오
174+
175+
@Test
176+
@WithMockUser
177+
@DisplayName("닉네임 수정 실패 - 중복된 닉네임 (U-100)")
178+
void updateNickname_Fail_Duplicated() throws Exception {
179+
doThrow(new BusinessException(UserErrorCode.NICKNAME_DUPLICATED))
180+
.when(userService).updateNickname(any(), any());
181+
182+
String jsonRequest = "{\"nickname\": \"existingNick\"}";
183+
184+
mockMvc.perform(patch("/api/v1/users/nickname")
185+
.with(csrf())
186+
.contentType(MediaType.APPLICATION_JSON)
187+
.content(jsonRequest))
188+
.andDo(print())
189+
.andExpect(status().isConflict())
190+
.andExpect(jsonPath("$.resultCode").value("U-100"))
191+
.andExpect(jsonPath("$.msg").value("이미 사용 중인 닉네임입니다."));
192+
}
193+
194+
@Test
195+
@WithMockUser
196+
@DisplayName("비밀번호 변경 실패 - 현재 비밀번호 불일치 (U-110)")
197+
void updatePassword_Fail_InvalidPassword() throws Exception {
198+
String jsonRequest = """
199+
{
200+
"currentPassword": "wrongPassword1!",
201+
"newPassword": "newPassword123!"
202+
}
203+
""";
204+
205+
doThrow(new BusinessException(UserErrorCode.INVALID_PASSWORD))
206+
.when(userService).updatePassword(any(), any());
207+
208+
mockMvc.perform(patch("/api/v1/users/password")
209+
.with(csrf())
210+
.contentType(MediaType.APPLICATION_JSON)
211+
.content(jsonRequest))
212+
.andDo(print())
213+
.andExpect(status().isBadRequest())
214+
.andExpect(jsonPath("$.resultCode").value("U-110"));
215+
}
216+
217+
@Test
218+
@WithMockUser
219+
@DisplayName("비밀번호 변경 실패 - 유효성 검사 에러 (VALIDATION_ERROR)")
220+
void updatePassword_Fail_ValidationError() throws Exception {
221+
String jsonRequest = "{\"currentPassword\": \"short\", \"newPassword\": \"short\"}";
222+
223+
mockMvc.perform(patch("/api/v1/users/password")
224+
.with(csrf())
225+
.contentType(MediaType.APPLICATION_JSON)
226+
.content(jsonRequest))
227+
.andDo(print())
228+
.andExpect(status().isBadRequest())
229+
.andExpect(jsonPath("$.resultCode").value("VALIDATION_ERROR"));
230+
}
231+
}

src/test/java/com/back/web7_9_codecrete_be/domain/users/controller/dummy.txt

Lines changed: 0 additions & 5 deletions
This file was deleted.

0 commit comments

Comments
 (0)