Skip to content

Commit 2d3e86f

Browse files
authored
[Docs] 에러 응답에 대한 문서화
2 parents d2a4df4 + 1d0fcf8 commit 2d3e86f

File tree

4 files changed

+181
-10
lines changed

4 files changed

+181
-10
lines changed

src/test/java/eatda/document/BaseDocumentTest.java

Lines changed: 29 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,11 @@
11
package eatda.document;
22

3+
import static org.mockito.Mockito.doReturn;
4+
import static org.springframework.restdocs.payload.JsonFieldType.STRING;
5+
import static org.springframework.restdocs.payload.PayloadDocumentation.fieldWithPath;
6+
37
import eatda.controller.web.jwt.JwtManager;
8+
import eatda.exception.BusinessErrorCode;
49
import eatda.service.auth.AuthService;
510
import eatda.service.member.MemberService;
611
import eatda.service.store.StoreService;
@@ -10,7 +15,6 @@
1015
import org.junit.jupiter.api.BeforeEach;
1116
import org.junit.jupiter.api.extension.ExtendWith;
1217
import org.mockito.junit.jupiter.MockitoExtension;
13-
import org.springframework.beans.factory.annotation.Autowired;
1418
import org.springframework.boot.test.context.SpringBootTest;
1519
import org.springframework.boot.test.web.server.LocalServerPort;
1620
import org.springframework.restdocs.RestDocumentationContextProvider;
@@ -24,15 +28,22 @@
2428
@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)
2529
public abstract class BaseDocumentTest {
2630

31+
protected static final RestDocsResponse ERROR_RESPONSE = new RestDocsResponse()
32+
.responseBodyField(
33+
fieldWithPath("errorCode").type(STRING).description("에러 코드"),
34+
fieldWithPath("message").type(STRING).description("에러 메시지")
35+
);
36+
private static final String MOCKED_ACCESS_TOKEN = "access-token";
37+
private static final String MOCKED_REFRESH_TOKEN = "refresh-token";
38+
2739
@MockitoBean
2840
protected AuthService authService;
2941
@MockitoBean
3042
protected MemberService memberService;
3143
@MockitoBean
3244
protected StoreService storeService;
33-
34-
@Autowired
35-
private JwtManager jwtManager;
45+
@MockitoBean
46+
protected JwtManager jwtManager;
3647
@LocalServerPort
3748
private int port;
3849

@@ -48,6 +59,14 @@ void setEnvironment(RestDocumentationContextProvider restDocumentation) {
4859
.build();
4960
}
5061

62+
@BeforeEach
63+
void mockingJwtManager() {
64+
doReturn(MOCKED_ACCESS_TOKEN).when(jwtManager).issueAccessToken(1L);
65+
doReturn(MOCKED_REFRESH_TOKEN).when(jwtManager).issueRefreshToken(1L);
66+
doReturn(1L).when(jwtManager).resolveAccessToken(MOCKED_ACCESS_TOKEN);
67+
doReturn(1L).when(jwtManager).resolveRefreshToken(MOCKED_REFRESH_TOKEN);
68+
}
69+
5170
protected final RestDocsRequest request() {
5271
return new RestDocsRequest();
5372
}
@@ -60,16 +79,20 @@ protected final RestDocsFilterBuilder document(String identifierPrefix, int stat
6079
return new RestDocsFilterBuilder(identifierPrefix, Integer.toString(statusCode));
6180
}
6281

82+
protected final RestDocsFilterBuilder document(String identifierPrefix, BusinessErrorCode errorCode) {
83+
return new RestDocsFilterBuilder(identifierPrefix, errorCode.name());
84+
}
85+
6386
protected final RequestSpecification given(RestDocumentationFilter documentationFilter) {
6487
return RestAssured.given(spec)
6588
.filter(documentationFilter);
6689
}
6790

6891
protected final String accessToken() {
69-
return jwtManager.issueAccessToken(1L);
92+
return MOCKED_ACCESS_TOKEN;
7093
}
7194

7295
protected final String refreshToken() {
73-
return jwtManager.issueRefreshToken(1L);
96+
return MOCKED_REFRESH_TOKEN;
7497
}
7598
}

src/test/java/eatda/document/auth/AuthDocumentTest.java

Lines changed: 58 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22

33
import static org.mockito.ArgumentMatchers.anyString;
44
import static org.mockito.Mockito.doReturn;
5+
import static org.mockito.Mockito.doThrow;
56
import static org.springframework.restdocs.headers.HeaderDocumentation.headerWithName;
67
import static org.springframework.restdocs.payload.JsonFieldType.BOOLEAN;
78
import static org.springframework.restdocs.payload.JsonFieldType.NUMBER;
@@ -16,11 +17,15 @@
1617
import eatda.document.RestDocsRequest;
1718
import eatda.document.RestDocsResponse;
1819
import eatda.document.Tag;
20+
import eatda.exception.BusinessErrorCode;
21+
import eatda.exception.BusinessException;
1922
import io.restassured.http.ContentType;
2023
import java.net.URI;
2124
import java.net.URISyntaxException;
2225
import org.junit.jupiter.api.Nested;
2326
import org.junit.jupiter.api.Test;
27+
import org.junit.jupiter.params.ParameterizedTest;
28+
import org.junit.jupiter.params.provider.EnumSource;
2429
import org.springframework.beans.factory.annotation.Value;
2530
import org.springframework.http.HttpHeaders;
2631

@@ -45,7 +50,7 @@ class RedirectOauthLoginPage {
4550
);
4651

4752
@Test
48-
void Oauth_로그인_페이지로_리다이렉트_할_수_있다() throws URISyntaxException {
53+
void Oauth_로그인_페이지_리다이렉트_성공() throws URISyntaxException {
4954
doReturn(new URI("http://localhost:8080")).when(authService).getOauthLoginUrl(anyString());
5055

5156
var document = document("auth/oauth-redirect", 302)
@@ -61,6 +66,22 @@ class RedirectOauthLoginPage {
6166
.then()
6267
.statusCode(302);
6368
}
69+
70+
@EnumSource(value = BusinessErrorCode.class, names = {"UNAUTHORIZED_ORIGIN"})
71+
@ParameterizedTest
72+
void Oauth_로그인_페이지_리다이렉트_실패(BusinessErrorCode errorCode) {
73+
doThrow(new BusinessException(errorCode)).when(authService).getOauthLoginUrl(anyString());
74+
75+
var document = document("auth/oauth-redirect", errorCode)
76+
.request(requestDocument)
77+
.response(ERROR_RESPONSE)
78+
.build();
79+
80+
given(document)
81+
.header(HttpHeaders.REFERER, origin)
82+
.when().get("/api/auth/login/oauth")
83+
.then().statusCode(errorCode.getStatus().value());
84+
}
6485
}
6586

6687
@Nested
@@ -105,6 +126,24 @@ class Login {
105126
.when().post("/api/auth/login")
106127
.then().statusCode(201);
107128
}
129+
130+
@EnumSource(value = BusinessErrorCode.class, names = {"UNAUTHORIZED_ORIGIN", "OAUTH_SERVER_ERROR"})
131+
@ParameterizedTest
132+
void 로그인_실패(BusinessErrorCode errorCode) {
133+
LoginRequest request = new LoginRequest("code", "http://localhost:3000");
134+
doThrow(new BusinessException(errorCode)).when(authService).login(request);
135+
136+
var document = document("auth/login", errorCode)
137+
.request(requestDocument)
138+
.response(ERROR_RESPONSE)
139+
.build();
140+
141+
given(document)
142+
.contentType(ContentType.JSON)
143+
.body(request)
144+
.when().post("/api/auth/login")
145+
.then().statusCode(errorCode.getStatus().value());
146+
}
108147
}
109148

110149
@Nested
@@ -138,5 +177,23 @@ class ReissueToken {
138177
.when().post("/api/auth/reissue")
139178
.then().statusCode(201);
140179
}
180+
181+
@EnumSource(value = BusinessErrorCode.class, names = {"EXPIRED_TOKEN", "UNAUTHORIZED_MEMBER"})
182+
@ParameterizedTest
183+
void 토큰_재발급_실패(BusinessErrorCode errorCode) {
184+
ReissueRequest request = new ReissueRequest(refreshToken());
185+
doThrow(new BusinessException(errorCode)).when(jwtManager).resolveRefreshToken(request.refreshToken());
186+
187+
var document = document("auth/reissue", errorCode)
188+
.request(requestDocument)
189+
.response(ERROR_RESPONSE)
190+
.build();
191+
192+
given(document)
193+
.contentType(ContentType.JSON)
194+
.body(request)
195+
.when().post("/api/auth/reissue")
196+
.then().statusCode(errorCode.getStatus().value());
197+
}
141198
}
142199
}

src/test/java/eatda/document/member/MemberDocumentTest.java

Lines changed: 68 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
import static org.mockito.ArgumentMatchers.eq;
66
import static org.mockito.Mockito.doNothing;
77
import static org.mockito.Mockito.doReturn;
8+
import static org.mockito.Mockito.doThrow;
89
import static org.springframework.restdocs.headers.HeaderDocumentation.headerWithName;
910
import static org.springframework.restdocs.payload.JsonFieldType.BOOLEAN;
1011
import static org.springframework.restdocs.payload.JsonFieldType.NUMBER;
@@ -18,9 +19,13 @@
1819
import eatda.document.RestDocsRequest;
1920
import eatda.document.RestDocsResponse;
2021
import eatda.document.Tag;
22+
import eatda.exception.BusinessErrorCode;
23+
import eatda.exception.BusinessException;
2124
import io.restassured.http.ContentType;
2225
import org.junit.jupiter.api.Nested;
2326
import org.junit.jupiter.api.Test;
27+
import org.junit.jupiter.params.ParameterizedTest;
28+
import org.junit.jupiter.params.provider.EnumSource;
2429
import org.springframework.http.HttpHeaders;
2530

2631
public class MemberDocumentTest extends BaseDocumentTest {
@@ -38,7 +43,7 @@ class CheckNickname {
3843
);
3944

4045
@Test
41-
void 중복되지_않는_닉네임을_확인할_수_있다() {
46+
void 중복_닉네임_확인_성공() {
4247
doNothing().when(memberService).validateNickname(anyString(), anyLong());
4348

4449
var document = document("member/nickname-check", 204)
@@ -52,6 +57,26 @@ class CheckNickname {
5257
.when().get("/api/member/nickname/check")
5358
.then().statusCode(204);
5459
}
60+
61+
@EnumSource(value = BusinessErrorCode.class,
62+
names = {"UNAUTHORIZED_MEMBER", "EXPIRED_TOKEN", "DUPLICATE_NICKNAME"})
63+
@ParameterizedTest
64+
void 중복_닉네임_확인_실패(BusinessErrorCode errorCode) {
65+
doThrow(new BusinessException(errorCode))
66+
.when(memberService).validateNickname(anyString(), anyLong());
67+
68+
var document = document("member/nickname-check", errorCode)
69+
.request(requestDocument)
70+
.response(ERROR_RESPONSE)
71+
.build();
72+
73+
given(document)
74+
.contentType(ContentType.JSON)
75+
.header(HttpHeaders.AUTHORIZATION, accessToken())
76+
.queryParam("nickname", "existing-nickname")
77+
.when().get("/api/member/nickname/check")
78+
.then().statusCode(errorCode.getStatus().value());
79+
}
5580
}
5681

5782
@Nested
@@ -67,7 +92,7 @@ class CheckPhoneNumber {
6792
);
6893

6994
@Test
70-
void 중복되지_않는_전화번호를_확인할_수_있다() {
95+
void 중복_전화번호_확인_성공() {
7196
doNothing().when(memberService).validatePhoneNumber(anyString(), anyLong());
7297

7398
var document = document("member/phone-number-check", 204)
@@ -81,6 +106,26 @@ class CheckPhoneNumber {
81106
.when().get("/api/member/phone-number/check")
82107
.then().statusCode(204);
83108
}
109+
110+
@EnumSource(value = BusinessErrorCode.class,
111+
names = {"UNAUTHORIZED_MEMBER", "EXPIRED_TOKEN", "DUPLICATE_PHONE_NUMBER"})
112+
@ParameterizedTest
113+
void 중복_전화번호_확인_실패(BusinessErrorCode errorCode) {
114+
doThrow(new BusinessException(errorCode))
115+
.when(memberService).validatePhoneNumber(anyString(), anyLong());
116+
117+
var document = document("member/phone-number-check", errorCode)
118+
.request(requestDocument)
119+
.response(ERROR_RESPONSE)
120+
.build();
121+
122+
given(document)
123+
.contentType(ContentType.JSON)
124+
.header(HttpHeaders.AUTHORIZATION, accessToken())
125+
.queryParam("phoneNumber", "01012345678")
126+
.when().get("/api/member/phone-number/check")
127+
.then().statusCode(errorCode.getStatus().value());
128+
}
84129
}
85130

86131
@Nested
@@ -126,5 +171,26 @@ class UpdateMember {
126171
.when().put("/api/member")
127172
.then().statusCode(200);
128173
}
174+
175+
@EnumSource(value = BusinessErrorCode.class,
176+
names = {"UNAUTHORIZED_MEMBER", "EXPIRED_TOKEN", "DUPLICATE_NICKNAME", "DUPLICATE_PHONE_NUMBER",
177+
"INVALID_MOBILE_PHONE_NUMBER", "INVALID_MARKETING_CONSENT"})
178+
@ParameterizedTest
179+
void 회원_정보_수정_실패(BusinessErrorCode errorCode) {
180+
MemberUpdateRequest request = new MemberUpdateRequest("update-nickname", "01012345678", "성북구", true);
181+
doThrow(new BusinessException(errorCode)).when(memberService).update(anyLong(), eq(request));
182+
183+
var document = document("member/update", errorCode)
184+
.request(requestDocument)
185+
.response(ERROR_RESPONSE)
186+
.build();
187+
188+
given(document)
189+
.contentType(ContentType.JSON)
190+
.header(HttpHeaders.AUTHORIZATION, accessToken())
191+
.body(request)
192+
.when().put("/api/member")
193+
.then().statusCode(errorCode.getStatus().value());
194+
}
129195
}
130196
}

src/test/java/eatda/document/store/StoreDocumentTest.java

Lines changed: 26 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33

44
import static org.mockito.ArgumentMatchers.anyString;
55
import static org.mockito.Mockito.doReturn;
6+
import static org.mockito.Mockito.doThrow;
67
import static org.springframework.restdocs.headers.HeaderDocumentation.headerWithName;
78
import static org.springframework.restdocs.payload.JsonFieldType.ARRAY;
89
import static org.springframework.restdocs.payload.JsonFieldType.STRING;
@@ -15,10 +16,14 @@
1516
import eatda.document.RestDocsRequest;
1617
import eatda.document.RestDocsResponse;
1718
import eatda.document.Tag;
19+
import eatda.exception.BusinessErrorCode;
20+
import eatda.exception.BusinessException;
1821
import io.restassured.http.ContentType;
1922
import java.util.List;
2023
import org.junit.jupiter.api.Nested;
2124
import org.junit.jupiter.api.Test;
25+
import org.junit.jupiter.params.ParameterizedTest;
26+
import org.junit.jupiter.params.provider.EnumSource;
2227
import org.springframework.http.HttpHeaders;
2328

2429
public class StoreDocumentTest extends BaseDocumentTest {
@@ -44,7 +49,7 @@ class SearchStores {
4449
);
4550

4651
@Test
47-
void 음식점_검색_결과를_반환한다() {
52+
void 음식점_검색_성공() {
4853
String query = "농민백암순대";
4954
StoreSearchResponses responses = new StoreSearchResponses(List.of(
5055
new StoreSearchResponse("17163273", "농민백암순대 본점", "서울 강남구 대치동 896-33"),
@@ -64,5 +69,25 @@ class SearchStores {
6469
.when().get("/api/shop/search")
6570
.then().statusCode(200);
6671
}
72+
73+
@EnumSource(value = BusinessErrorCode.class,
74+
names = {"UNAUTHORIZED_MEMBER", "EXPIRED_TOKEN", "MAP_SERVER_ERROR"})
75+
@ParameterizedTest
76+
void 음식점_검색_실패(BusinessErrorCode errorCode) {
77+
String query = "농민백암순대";
78+
doThrow(new BusinessException(errorCode)).when(storeService).searchStores(anyString());
79+
80+
var document = document("store/search", errorCode)
81+
.request(requestDocument)
82+
.response(ERROR_RESPONSE)
83+
.build();
84+
85+
given(document)
86+
.contentType(ContentType.JSON)
87+
.header(HttpHeaders.AUTHORIZATION, accessToken())
88+
.queryParam("query", query)
89+
.when().get("/api/shop/search")
90+
.then().statusCode(errorCode.getStatus().value());
91+
}
6792
}
6893
}

0 commit comments

Comments
 (0)