diff --git a/src/main/java/com/server/bbo_gak/domain/card/dto/response/CardGetResponse.java b/src/main/java/com/server/bbo_gak/domain/card/dto/response/CardGetResponse.java index 96248d7..298e52a 100644 --- a/src/main/java/com/server/bbo_gak/domain/card/dto/response/CardGetResponse.java +++ b/src/main/java/com/server/bbo_gak/domain/card/dto/response/CardGetResponse.java @@ -7,10 +7,9 @@ import com.server.bbo_gak.global.utils.BaseDateTimeFormatter; import java.util.List; import java.util.Optional; -import lombok.AccessLevel; import lombok.Builder; -@Builder(access = AccessLevel.PRIVATE) +@Builder public record CardGetResponse( String title, String content, diff --git a/src/main/java/com/server/bbo_gak/domain/card/dto/response/TagGetResponse.java b/src/main/java/com/server/bbo_gak/domain/card/dto/response/TagGetResponse.java index ac3fe8b..1dbac08 100644 --- a/src/main/java/com/server/bbo_gak/domain/card/dto/response/TagGetResponse.java +++ b/src/main/java/com/server/bbo_gak/domain/card/dto/response/TagGetResponse.java @@ -1,10 +1,9 @@ package com.server.bbo_gak.domain.card.dto.response; import com.server.bbo_gak.domain.card.entity.Tag; -import lombok.AccessLevel; import lombok.Builder; -@Builder(access = AccessLevel.PRIVATE) +@Builder public record TagGetResponse( Long id, String name, diff --git a/src/test/java/com/server/bbo_gak/domain/card/controller/CardControllerTest.java b/src/test/java/com/server/bbo_gak/domain/card/controller/CardControllerTest.java index 1c21fab..113115f 100644 --- a/src/test/java/com/server/bbo_gak/domain/card/controller/CardControllerTest.java +++ b/src/test/java/com/server/bbo_gak/domain/card/controller/CardControllerTest.java @@ -27,14 +27,19 @@ import com.server.bbo_gak.domain.card.dto.request.CardCreateRequest; import com.server.bbo_gak.domain.card.dto.request.CardTitleUpdateRequest; import com.server.bbo_gak.domain.card.dto.request.CardTypeUpdateRequest; +import com.server.bbo_gak.domain.card.dto.response.CardGetResponse; +import com.server.bbo_gak.domain.card.dto.response.TagGetResponse; import com.server.bbo_gak.domain.card.entity.Card; import com.server.bbo_gak.domain.card.entity.CardType; import com.server.bbo_gak.domain.card.entity.CardTypeValueGroup; import com.server.bbo_gak.global.AbstractRestDocsTests; import com.server.bbo_gak.global.RestDocsFactory; import jakarta.persistence.EntityManager; +import java.time.LocalDateTime; +import java.time.format.DateTimeFormatter; import java.util.Arrays; import java.util.List; +import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Nested; import org.junit.jupiter.api.Test; import org.springframework.beans.factory.annotation.Autowired; @@ -86,38 +91,52 @@ class 카드_타입_카운트_조회 { @Nested class 카드_단건_조회 { + private CardGetResponse response; + + @BeforeEach + void setUp() { + TagGetResponse tag1 = TagGetResponse.builder() + .id(1L) + .name("스프링") + .type("역량") + .build(); + + List tagList = List.of(tag1); + + List cardTypeValueList = List.of("Type1", "Type2"); + + CardGetResponse response = CardGetResponse.builder() + .title("test_title") + .content("test_content") + .createdDate(LocalDateTime.now().format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss"))) + .updatedDate(LocalDateTime.now().format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss"))) + .recruitTitle("Recruit Title") + .cardTypeValueGroup("Type1") + .cardTypeValueList(cardTypeValueList) + .tagList(tagList) + .build(); + } + @Test public void 성공() throws Exception { - mockMvc.perform(get(DEFAULT_URL + "/cards/{card-id}", 1).contentType(MediaType.APPLICATION_JSON) - .accept(MediaType.APPLICATION_JSON)).andExpect(status().isOk()).andDo( - document("[select] 카드 단건 조회", preprocessResponse(prettyPrint()), resource( - ResourceSnippetParameters.builder().description("카드 단건 조회").tags("Card") - .pathParameters(parameterWithName("card-id").description("card-id")) - .responseSchema(Schema.schema("CardGetResponse")) - .responseFields(fieldWithPath("title").type(JsonFieldType.STRING).description("Card 제목"), - fieldWithPath("content").type(JsonFieldType.STRING).description("Card 내용"), - fieldWithPath("recruitTitle").type(JsonFieldType.STRING).optional().description("공고 제목"), - fieldWithPath("cardTypeValueList").type(JsonFieldType.ARRAY).description("Card 타입값 리스트"), - fieldWithPath("createdDate").type(JsonFieldType.STRING).description("Card 생성일시"), - fieldWithPath("updatedDate").type(JsonFieldType.STRING).description("Card 수정일시"), - fieldWithPath("cardTypeValueGroup").type(JsonFieldType.STRING).description("Card 그룹 이름"), - fieldWithPath("tagList.[].id").type(JsonFieldType.NUMBER).description("태그 ID"), - fieldWithPath("tagList.[].name").type(JsonFieldType.STRING).description("태그 이름"), - fieldWithPath("tagList.[].type").type(JsonFieldType.STRING).description("태그 타입")) - .build()))); + mockMvc.perform( + restDocsFactory.createRequest(DEFAULT_URL + "/cards/{card-id}", null, HttpMethod.GET, objectMapper, + 1L)) + .andExpect(status().isOk()) + .andDo( + restDocsFactory.getSuccessResource("[select] 카드 단건 조회", "카드 단건 조회", "Card", + null, response)); } @Test public void 카드_찾기_실패() throws Exception { - mockMvc.perform(get(DEFAULT_URL + "/cards/{card-id}", 9999).contentType(MediaType.APPLICATION_JSON) - .accept(MediaType.APPLICATION_JSON)).andExpect(status().isNotFound()).andDo( - document("[select] 카드 찾기 실패", preprocessResponse(prettyPrint()), resource( - ResourceSnippetParameters.builder().description("카드 단건 조회").tags("Card") - .pathParameters(parameterWithName("card-id").description("card-id")) - .responseSchema(Schema.schema("ErrorResponse")).responseFields( - fieldWithPath("message").type(JsonFieldType.STRING).description("Error message"), - fieldWithPath("status").type(JsonFieldType.STRING).description("HTTP status code")).build()))); - + mockMvc.perform( + restDocsFactory.createRequest(DEFAULT_URL + "/cards/{card-id}", null, HttpMethod.GET, objectMapper, + 9999L)) + .andExpect(status().isNotFound()) + .andDo( + restDocsFactory.getFailureResource("[select] 카드 찾기 실패", "Card", + null)); } } diff --git a/src/test/java/com/server/bbo_gak/global/RestDocsFactory.java b/src/test/java/com/server/bbo_gak/global/RestDocsFactory.java index 2ddfe0f..b92319f 100644 --- a/src/test/java/com/server/bbo_gak/global/RestDocsFactory.java +++ b/src/test/java/com/server/bbo_gak/global/RestDocsFactory.java @@ -325,28 +325,40 @@ public FieldDescriptor[] getFieldsList(T dto) { } private void generateFieldDescriptors(T dto, String pathPrefix, List fields) { + if (isSimpleType(dto)) { + return; + } + Field[] declaredFields = dto.getClass().getDeclaredFields(); for (Field field : declaredFields) { field.setAccessible(true); - String name = pathPrefix + field.getName(); - JsonFieldType type = determineFieldType(field.getType()); - Object value = getFieldValue(dto, field); - - if (type == JsonFieldType.OBJECT) { - // 중첩된 객체 처리 - fields.add(fieldWithPath(name) - .type(JsonFieldType.OBJECT) - .description(field.getName()) - .optional()); - if (value != null) { - generateFieldDescriptors(value, name + ".", fields); + String fieldPath = pathPrefix + field.getName(); + JsonFieldType fieldType = determineFieldType(field.getType()); + Object fieldValue = getFieldValue(dto, field); + + FieldDescriptor descriptor = fieldWithPath(fieldPath) + .type(fieldType) + .description(field.getName()) + .optional(); + + if (fieldType != JsonFieldType.OBJECT && fieldType != JsonFieldType.ARRAY) { + descriptor.attributes( + Attributes.key("example").value(fieldValue != null ? fieldValue.toString() : "null")); + } + + fields.add(descriptor); + + // 리스트 타입 처리 + if (fieldType == JsonFieldType.ARRAY && fieldValue instanceof List list) { + if (!list.isEmpty()) { + Object firstElement = list.getFirst(); + generateFieldDescriptors(firstElement, fieldPath + "[].", fields); } - } else { - fields.add(fieldWithPath(name) - .type(type) - .description(field.getName()) - .optional() - .attributes(Attributes.key("example").value(value != null ? value.toString() : "null"))); + } + + // 오브젝트 타입 처리 + if (fieldType == JsonFieldType.OBJECT && fieldValue != null) { + generateFieldDescriptors(fieldValue, fieldPath + ".", fields); } } } @@ -359,6 +371,10 @@ private Object getFieldValue(T dto, Field field) { } } + private boolean isSimpleType(Object dto) { + return dto instanceof String || dto instanceof Number || dto instanceof Boolean || dto.getClass().isEnum(); + } + private JsonFieldType determineFieldType(Class fieldType) { if (fieldType == String.class || fieldType.isEnum()) { return JsonFieldType.STRING;