Skip to content

Commit

Permalink
GETP-143 test: 피플 목록 조회 컨트롤러 단위 테스트 및 API 문서 작성 (#67)
Browse files Browse the repository at this point in the history
* GETP-143 feat: 페이지 객체 DTO `PageResponse` 구현

* GETP-143 test: 피플 목록 조회 컨트롤러 단위 테스트 및 API 문서 작성
  • Loading branch information
scv1702 committed Jun 9, 2024
1 parent 2976982 commit f08a82e
Show file tree
Hide file tree
Showing 12 changed files with 215 additions and 12 deletions.
5 changes: 4 additions & 1 deletion src/docs/asciidoc/index.adoc
Original file line number Diff line number Diff line change
Expand Up @@ -34,4 +34,7 @@ include::{docdir}/member/upload-profile-image.adoc[]
include::{docdir}/people/create-people.adoc[]

=== 피플 상세 조회
include::{docdir}/people/get-people.adoc[]
include::{docdir}/people/get-people.adoc[]

=== 피플 목록 조회
include::{docdir}/people/get-card-people-page.adoc[]
1 change: 1 addition & 0 deletions src/docs/asciidoc/people/get-card-people-page.adoc
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
operation::/get-card-people-page/get-card-people-page[snippets="http-request,query-parameters,http-response,response-fields-data"]
Original file line number Diff line number Diff line change
Expand Up @@ -6,13 +6,13 @@
import es.princip.getp.domain.people.dto.response.people.DetailPeopleResponse;
import es.princip.getp.domain.people.dto.response.people.PublicDetailPeopleResponse;
import es.princip.getp.domain.people.service.PeopleService;
import es.princip.getp.global.domain.dto.response.PageResponse;
import es.princip.getp.global.security.details.PrincipalDetails;
import es.princip.getp.global.support.ControllerSupport;
import es.princip.getp.global.util.ApiResponse;
import es.princip.getp.global.util.ApiResponse.ApiSuccessResult;
import jakarta.validation.Valid;
import lombok.RequiredArgsConstructor;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
import org.springframework.data.domain.Sort;
import org.springframework.data.web.PageableDefault;
Expand Down Expand Up @@ -72,9 +72,9 @@ public ResponseEntity<ApiSuccessResult<?>> getPeople(@PathVariable Long peopleId
* @return 정렬 기준에 해당되는 피플 정보 목록
*/
@GetMapping
public ResponseEntity<ApiSuccessResult<Page<CardPeopleResponse>>> getCardPeoplePage(
@PageableDefault(sort = "PEOPLE_ID", direction = Sort.Direction.DESC) Pageable pageable) {
Page<CardPeopleResponse> response = peopleService.getCardPeoplePage(pageable);
public ResponseEntity<ApiSuccessResult<PageResponse<CardPeopleResponse>>> getCardPeoplePage(
@PageableDefault(sort = "peopleId", direction = Sort.Direction.DESC) Pageable pageable) {
PageResponse<CardPeopleResponse> response = PageResponse.from(peopleService.getCardPeoplePage(pageable));
return ResponseEntity.ok().body(ApiResponse.success(HttpStatus.OK, response));
}
}
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
package es.princip.getp.domain.people.domain.enums;

import com.fasterxml.jackson.annotation.JsonCreator;
import es.princip.getp.global.util.StringUtil;

import java.util.stream.Stream;

public enum PeopleOrder {
Expand All @@ -9,8 +11,12 @@ public enum PeopleOrder {
@JsonCreator
public static PeopleOrder parsing(String inputValue) {
return Stream.of(PeopleOrder.values())
.filter(peopleOrder -> peopleOrder.toString().equals(inputValue.toUpperCase()))
.filter(peopleOrder -> peopleOrder.toString().equals(StringUtil.camelToSnake(inputValue).toUpperCase()))
.findFirst()
.orElse(null);
}

public static PeopleOrder get(String value) {
return PeopleOrder.valueOf(StringUtil.camelToSnake(value).toUpperCase());
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,7 @@ private OrderSpecifier<?> getOrderSpecifier(Order order, PeopleOrder peopleOrder
private OrderSpecifier<?>[] getPeopleOrderSpecifiers(Sort sort) {
List<OrderSpecifier<?>> orderSpecifiers = new ArrayList<>();
sort.stream().forEach(order -> {
PeopleOrder peopleOrder = PeopleOrder.valueOf(order.getProperty());
PeopleOrder peopleOrder = PeopleOrder.get(order.getProperty());
OrderSpecifier<?> orderSpecifier = getOrderSpecifier(order, peopleOrder);
orderSpecifiers.add(orderSpecifier);
});
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,81 @@
package es.princip.getp.global.domain.dto.response;

import lombok.Builder;
import lombok.Getter;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Sort;

import java.util.List;

@Getter
public class PageResponse<T> {
private final List<T> content;
private final PageInfo pageInfo;

private PageResponse(List<T> content, PageInfo pageInfo) {
this.content = content;
this.pageInfo = pageInfo;
}

public static <T> PageResponse<T> from(Page<T> page) {
PageInfo pageInfo = PageInfo.builder()
.totalPages(page.getTotalPages())
.totalElements(page.getTotalElements())
.size(page.getSize())
.number(page.getNumber())
.numberOfElements(page.getNumberOfElements())
.first(page.isFirst())
.last(page.isLast())
.empty(page.isEmpty())
.sort(page.getSort())
.build();
return new PageResponse<>(page.getContent(), pageInfo);
}

@Getter
static class SortInfo {
private final String property;
private final String direction;

public SortInfo(Sort.Order order) {
this.property = order.getProperty();
this.direction = order.getDirection().name();
}
}

@Getter
static class PageInfo {
private final int totalPages;
private final long totalElements;
private final int size;
private final int number;
private final int numberOfElements;
private final boolean first;
private final boolean last;
private final boolean empty;
private final SortInfo sort;

@Builder
public PageInfo(
int totalPages,
long totalElements,
int size,
int number,
int numberOfElements,
boolean first,
boolean last,
boolean empty,
Sort sort
) {
this.totalPages = totalPages;
this.totalElements = totalElements;
this.size = size;
this.number = number;
this.numberOfElements = numberOfElements;
this.first = first;
this.last = last;
this.empty = empty;
this.sort = sort.stream().map(SortInfo::new).findFirst().orElse(null);
}
}
}
15 changes: 15 additions & 0 deletions src/main/java/es/princip/getp/global/util/StringUtil.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
package es.princip.getp.global.util;

public class StringUtil {

public static String camelToSnake(String camelCase) {
if (camelCase == null || camelCase.isEmpty()) {
return camelCase;
}

String regex = "([a-z])([A-Z]+)";
String replacement = "$1_$2";

return camelCase.replaceAll(regex, replacement);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
import es.princip.getp.domain.member.domain.entity.Member;
import es.princip.getp.domain.people.domain.entity.People;
import es.princip.getp.domain.people.dto.request.CreatePeopleRequest;
import es.princip.getp.domain.people.dto.response.people.CardPeopleResponse;
import es.princip.getp.domain.people.fixture.PeopleFixture;
import es.princip.getp.domain.people.service.PeopleService;
import es.princip.getp.global.mock.WithCustomMockUser;
Expand All @@ -15,6 +16,10 @@
import org.mockito.Mockito;
import org.springframework.boot.test.autoconfigure.web.servlet.WebMvcTest;
import org.springframework.boot.test.mock.mockito.MockBean;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Pageable;
import org.springframework.data.domain.Sort;
import org.springframework.security.access.AccessDeniedException;
import org.springframework.test.web.servlet.ResultActions;

Expand All @@ -25,14 +30,15 @@
import static es.princip.getp.domain.people.fixture.PeopleProfileFixture.createPeopleProfile;
import static es.princip.getp.global.support.FieldDescriptorHelper.getDescriptor;
import static es.princip.getp.global.support.HeaderDescriptorHelper.authorizationHeaderDescriptor;
import static es.princip.getp.global.support.PageResponseDescriptor.pageResponseFieldDescriptors;
import static es.princip.getp.global.support.PayloadDocumentationHelper.responseFields;
import static org.assertj.core.api.Assertions.assertThatThrownBy;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.BDDMockito.given;
import static org.springframework.http.MediaType.APPLICATION_JSON;
import static org.springframework.restdocs.headers.HeaderDocumentation.*;
import static org.springframework.restdocs.payload.PayloadDocumentation.requestFields;
import static org.springframework.restdocs.request.RequestDocumentation.parameterWithName;
import static org.springframework.restdocs.request.RequestDocumentation.pathParameters;
import static org.springframework.restdocs.request.RequestDocumentation.*;
import static org.springframework.restdocs.snippet.Attributes.key;
import static org.springframework.test.web.servlet.result.MockMvcResultHandlers.print;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;
Expand All @@ -43,6 +49,56 @@ class PeopleControllerTest extends AbstractControllerTest {
@MockBean
private PeopleService peopleService;

@DisplayName("사용자는 피플 목록을 조회할 수 있다.")
@Nested
class GetCardPeoplePage {
private final int page = 0;
private final int size = 3;
private final Sort sort = Sort.by(Sort.Order.desc("peopleId"));

private ResultActions perform() throws Exception {
return mockMvc.perform(get("/people")
.queryParam("page", String.valueOf(page))
.queryParam("size", String.valueOf(size))
.queryParam("sort", "peopleId,desc")
.contentType(APPLICATION_JSON));
}

@Test
public void getCardPeoplePage() throws Exception {
Pageable pageable = PageRequest.of(page, size, sort);
Page<CardPeopleResponse> cardPeoplePage = PeopleFixture.createCardPeopleResponsePage(pageable, size);
given(peopleService.getCardPeoplePage(any(Pageable.class))).willReturn(cardPeoplePage);

perform()
.andExpect(status().isOk())
.andDo(
restDocs.document(
queryParameters(
parameterWithName("page").description("페이지 번호")
.optional().attributes(key("default").value("0")),
parameterWithName("size").description("페이지 크기")
.optional().attributes(key("default").value("10")),
parameterWithName("sort").description("정렬 방식")
.optional().attributes(key("default").value("peopleId,desc"))
),
responseFields(
getDescriptor("content[].peopleId", "피플 ID"),
getDescriptor("content[].nickname", "닉네임"),
getDescriptor("content[].peopleType", "피플 유형")
.attributes(key("format").value("TEAM, INDIVIDUAL")),
getDescriptor("content[].profileImageUri", "프로필 이미지 URI"),
getDescriptor("content[].profile.activityArea", "활동 지역"),
getDescriptor("content[].profile.hashtags[].value", "해시태그"),
getDescriptor("content[].profile.completedProjectsCount", "완수한 프로젝트 수"),
getDescriptor("content[].profile.interestsCount", "받은 관심 수")
).and(pageResponseFieldDescriptors())
)
)
.andDo(print());
}
}

@DisplayName("사용자는 피플의 상세 정보를 조회할 수 있다.")
@Nested
class GetPeople {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,9 @@
import es.princip.getp.domain.people.dto.request.CreatePeopleRequest;
import es.princip.getp.domain.people.dto.request.UpdatePeopleRequest;
import es.princip.getp.domain.people.dto.response.people.CardPeopleResponse;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageImpl;
import org.springframework.data.domain.Pageable;

import java.util.List;
import java.util.stream.LongStream;
Expand Down Expand Up @@ -52,7 +55,7 @@ public static List<People> createPeopleList(List<Member> memberList) {
}

public static List<CardPeopleResponse> createCardPeopleResponses(int count) {
return LongStream.range(0, count)
return LongStream.range(1, count + 1)
.mapToObj(i -> CardPeopleResponse.from(
i,
NICKNAME,
Expand All @@ -61,4 +64,8 @@ public static List<CardPeopleResponse> createCardPeopleResponses(int count) {
PeopleProfileFixture.createCardPeopleProfileResponse()))
.toList();
}

public static Page<CardPeopleResponse> createCardPeopleResponsePage(Pageable pageable, int count) {
return new PageImpl<>(createCardPeopleResponses(count), pageable, count);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -71,7 +71,7 @@ public static CardPeopleProfileResponse createCardPeopleProfileResponse() {
return new CardPeopleProfileResponse(
ACTIVITY_AREA,
HASHTAGS,
null,
null);
0,
0);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
package es.princip.getp.global.support;

import org.springframework.restdocs.payload.FieldDescriptor;

import static es.princip.getp.global.support.FieldDescriptorHelper.getDescriptor;

public class PageResponseDescriptor {

public static FieldDescriptor[] pageResponseFieldDescriptors() {
return new FieldDescriptor[] {
getDescriptor("pageInfo.totalPages", "전체 페이지 수"),
getDescriptor("pageInfo.totalElements", "전체 요소 수"),
getDescriptor("pageInfo.size", "페이지 크기"),
getDescriptor("pageInfo.number", "현재 페이지 번호"),
getDescriptor("pageInfo.numberOfElements", "현재 페이지 요소 수"),
getDescriptor("pageInfo.first", "첫 페이지 여부"),
getDescriptor("pageInfo.last", "마지막 페이지 여부"),
getDescriptor("pageInfo.empty", "비어있는 페이지 여부"),
getDescriptor("pageInfo.sort.property", "정렬 속성"),
getDescriptor("pageInfo.sort.direction", "정렬 방향")
};
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
|===
|Parameter|Description|Optional|Default

{{#parameters}}
|{{#tableCellContent}}`+{{name}}+`{{/tableCellContent}}
|{{#tableCellContent}}{{description}}{{/tableCellContent}}
|{{#tableCellContent}}{{#optional}}Yes{{/optional}}{{^optional}}No{{/optional}}{{/tableCellContent}}
|{{#tableCellContent}}{{default}}{{/tableCellContent}}

{{/parameters}}
|===

0 comments on commit f08a82e

Please sign in to comment.