From 713e08cc4054a8f9b3efb9fa68af2cf858a25a09 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EC=9D=B4=EC=A3=BC=EC=98=81?= <141599648+ljy1348@users.noreply.github.com> Date: Fri, 11 Sep 2026 23:46:33 +0900 Subject: [PATCH 1/2] =?UTF-8?q?[FEAT]=20=EC=84=9C=EC=9E=AC=20=EB=85=B8?= =?UTF-8?q?=EB=B2=A8=20=EC=A0=95=EB=B3=B4=EC=97=90=20=EC=9E=91=EA=B0=80?= =?UTF-8?q?=EB=AA=85=EC=9D=84=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../UserNovelAndNovelGetResponse.java | 2 ++ .../UserNovelAndNovelGetResponseTest.java | 30 +++++++++++++++++++ 2 files changed, 32 insertions(+) create mode 100644 src/test/java/org/websoso/WSSServer/dto/userNovel/UserNovelAndNovelGetResponseTest.java diff --git a/src/main/java/org/websoso/WSSServer/dto/userNovel/UserNovelAndNovelGetResponse.java b/src/main/java/org/websoso/WSSServer/dto/userNovel/UserNovelAndNovelGetResponse.java index aef49bd66..2736c285b 100644 --- a/src/main/java/org/websoso/WSSServer/dto/userNovel/UserNovelAndNovelGetResponse.java +++ b/src/main/java/org/websoso/WSSServer/dto/userNovel/UserNovelAndNovelGetResponse.java @@ -13,6 +13,7 @@ public record UserNovelAndNovelGetResponse( Long userNovelId, Long novelId, String title, + String author, String novelImage, Float novelRating, String readStatus, @@ -41,6 +42,7 @@ public static UserNovelAndNovelGetResponse from(UserNovel userNovel, Float novel userNovel.getUserNovelId(), novel.getNovelId(), novel.getTitle(), + novel.getAuthor(), novel.getNovelImage(), novelRatingAvg, userNovel.getStatus() != null diff --git a/src/test/java/org/websoso/WSSServer/dto/userNovel/UserNovelAndNovelGetResponseTest.java b/src/test/java/org/websoso/WSSServer/dto/userNovel/UserNovelAndNovelGetResponseTest.java new file mode 100644 index 000000000..433c0092f --- /dev/null +++ b/src/test/java/org/websoso/WSSServer/dto/userNovel/UserNovelAndNovelGetResponseTest.java @@ -0,0 +1,30 @@ +package org.websoso.WSSServer.dto.userNovel; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.mockito.BDDMockito.given; +import static org.mockito.Mockito.mock; + +import java.util.List; +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; +import org.websoso.WSSServer.library.domain.UserNovel; +import org.websoso.WSSServer.novel.domain.Novel; + +class UserNovelAndNovelGetResponseTest { + + @DisplayName("서재의 노벨 정보에 작가명을 포함한다") + @Test + void includesNovelAuthor() { + UserNovel userNovel = mock(UserNovel.class); + Novel novel = mock(Novel.class); + given(userNovel.getNovel()).willReturn(novel); + given(userNovel.getUserNovelAttractivePoints()).willReturn(List.of()); + given(userNovel.getUserNovelKeywords()).willReturn(List.of()); + given(novel.getAuthor()).willReturn("테스트 작가"); + + UserNovelAndNovelGetResponse response = UserNovelAndNovelGetResponse.from( + userNovel, 4.5f, List.of()); + + assertThat(response.author()).isEqualTo("테스트 작가"); + } +} From 94cab387f59fc4523c6b96a2c4e626a33ff2ec04 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EC=9D=B4=EC=A3=BC=EC=98=81?= <141599648+ljy1348@users.noreply.github.com> Date: Sat, 12 Sep 2026 00:14:31 +0900 Subject: [PATCH 2/2] =?UTF-8?q?[TEST]=20=EC=84=9C=EC=9E=AC=20=EB=85=B8?= =?UTF-8?q?=EB=B2=A8=20=EC=9E=91=EA=B0=80=EB=AA=85=20=EC=9D=91=EB=8B=B5=20?= =?UTF-8?q?=EB=AC=B8=EC=84=9C=ED=99=94?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../controller/GetUserNovelsV2DocsTest.java | 129 ++++++++++++++++++ 1 file changed, 129 insertions(+) create mode 100644 src/test/java/org/websoso/WSSServer/user/controller/GetUserNovelsV2DocsTest.java diff --git a/src/test/java/org/websoso/WSSServer/user/controller/GetUserNovelsV2DocsTest.java b/src/test/java/org/websoso/WSSServer/user/controller/GetUserNovelsV2DocsTest.java new file mode 100644 index 000000000..bd8ca62c7 --- /dev/null +++ b/src/test/java/org/websoso/WSSServer/user/controller/GetUserNovelsV2DocsTest.java @@ -0,0 +1,129 @@ +package org.websoso.WSSServer.user.controller; + +import static com.epages.restdocs.apispec.ResourceDocumentation.parameterWithName; +import static com.epages.restdocs.apispec.ResourceDocumentation.resource; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.ArgumentMatchers.eq; +import static org.mockito.ArgumentMatchers.isNull; +import static org.mockito.BDDMockito.given; +import static org.springframework.http.MediaType.APPLICATION_JSON; +import static org.springframework.restdocs.mockmvc.MockMvcRestDocumentation.document; +import static org.springframework.restdocs.mockmvc.RestDocumentationRequestBuilders.get; +import static org.springframework.restdocs.payload.JsonFieldType.ARRAY; +import static org.springframework.restdocs.payload.JsonFieldType.BOOLEAN; +import static org.springframework.restdocs.payload.JsonFieldType.NUMBER; +import static org.springframework.restdocs.payload.JsonFieldType.STRING; +import static org.springframework.restdocs.payload.PayloadDocumentation.fieldWithPath; +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.content; +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.jsonPath; +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; +import static org.websoso.WSSServer.support.auth.TestBearerToken.accessToken; + +import com.epages.restdocs.apispec.ResourceSnippetParameters; +import com.epages.restdocs.apispec.Schema; +import java.time.LocalDate; +import java.util.List; +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.boot.test.autoconfigure.restdocs.AutoConfigureRestDocs; +import org.springframework.boot.test.mock.mockito.MockBean; +import org.springframework.test.web.servlet.MockMvc; +import org.websoso.WSSServer.dto.userNovel.UserNovelAndNovelGetResponse; +import org.websoso.WSSServer.dto.userNovel.UserNovelsV2GetResponse; +import org.websoso.WSSServer.library.service.UserNovelService; +import org.websoso.WSSServer.support.auth.AuthenticatedControllerTest; +import org.websoso.WSSServer.user.domain.User; +import org.websoso.WSSServer.user.service.UserService; + +@AutoConfigureRestDocs +@AuthenticatedControllerTest(UserController.class) +class GetUserNovelsV2DocsTest { + + private static final long VISITOR_ID = 42L; + private static final long OWNER_ID = 10034L; + + @Autowired + private MockMvc mockMvc; + + @MockBean + private UserService userService; + + @MockBean + private UserNovelService userNovelService; + + @BeforeEach + void setUp() { + given(userService.getUserOrException(VISITOR_ID)).willReturn(org.mockito.Mockito.mock(User.class)); + } + + @DisplayName("서재 작품의 작가명을 문서화한다") + @Test + void documentUserNovelsV2() throws Exception { + given(userNovelService.getUserNovelsAndNovelsV2( + any(User.class), eq(OWNER_ID), isNull(), eq(10), eq("created_desc"), + isNull(), isNull(), isNull(), isNull(), isNull(), isNull(), isNull(), isNull(), isNull())) + .willReturn(userNovelsResponse()); + + mockMvc.perform(get("/users/{userId}/novels/v2", OWNER_ID) + .queryParam("size", "10") + .with(accessToken(VISITOR_ID))) + .andExpect(status().isOk()) + .andExpect(content().contentTypeCompatibleWith(APPLICATION_JSON)) + .andExpect(jsonPath("$.userNovels[0].author").value("작가명")) + .andDo(document("users-novels-v2-get", + resource(ResourceSnippetParameters.builder() + .tag("User Novel") + .summary("사용자 서재 작품 조회 V2") + .description("사용자의 서재 작품을 조회합니다. 각 작품은 제목과 함께 작가명을 반환합니다.") + .pathParameters(parameterWithName("userId").description("서재 소유자 사용자 ID")) + .queryParameters(parameterWithName("size").description("조회할 작품 개수")) + .responseSchema(Schema.schema("UserNovelsV2GetResponse")) + .responseFields( + fieldWithPath("userNovelCount").type(NUMBER).description("필터에 해당하는 전체 작품 수"), + fieldWithPath("isLoadable").type(BOOLEAN).description("다음 페이지 존재 여부"), + fieldWithPath("nextCursor").type(STRING).description("다음 페이지 커서"), + fieldWithPath("userNovels[]").type(ARRAY).description("서재 작품 목록"), + fieldWithPath("userNovels[].userNovelId").type(NUMBER).description("서재 작품 ID"), + fieldWithPath("userNovels[].novelId").type(NUMBER).description("작품 ID"), + fieldWithPath("userNovels[].title").type(STRING).description("작품 제목"), + fieldWithPath("userNovels[].author").type(STRING).description("작가명"), + fieldWithPath("userNovels[].novelImage").type(STRING).description("작품 이미지 URL"), + fieldWithPath("userNovels[].novelRating").type(NUMBER).description("작품 전체 평균 평점"), + fieldWithPath("userNovels[].readStatus").type(STRING).description("독서 상태"), + fieldWithPath("userNovels[].isInterest").type(BOOLEAN).description("관심 등록 여부"), + fieldWithPath("userNovels[].userNovelRating").type(NUMBER) + .description("서재 소유자가 직접 남긴 평점"), + fieldWithPath("userNovels[].attractivePoints[]").type(ARRAY) + .description("서재 소유자가 선택한 매력 포인트"), + fieldWithPath("userNovels[].startDate").type(STRING).description("독서 시작일"), + fieldWithPath("userNovels[].endDate").type(STRING).description("독서 종료일"), + fieldWithPath("userNovels[].keywords[]").type(ARRAY) + .description("서재 소유자가 선택한 키워드"), + fieldWithPath("userNovels[].myFeeds[]").type(ARRAY) + .description("서재 소유자가 이 작품에 작성한 피드 내용")) + .build()))); + } + + private UserNovelsV2GetResponse userNovelsResponse() { + UserNovelAndNovelGetResponse userNovel = new UserNovelAndNovelGetResponse( + 1210L, + 2706L, + "작품명", + "작가명", + "https://image.websoso.kr/novel/2706.jpg", + 4.3f, + "WATCHING", + true, + 3.0f, + List.of("세계관"), + LocalDate.of(2026, 9, 1), + LocalDate.of(2026, 9, 10), + List.of("성장물"), + List.of("재미있게 읽는 중") + ); + + return new UserNovelsV2GetResponse(1L, true, "next-cursor", List.of(userNovel)); + } +}