게시글 여러개 조회

단건 조회에서 조금 더 나아가 여러개의 글을 조회하는 API 를 만들어보자.

이전 게시글에서 리팩토링 했던 PostResponse 형태로 응답을 반환하는건 유지하고 10자 제한은 적용하지 않았다.

 

PostController

@GetMapping("/posts")
public List<PostResponse> getList() {
    return postService.getList();
}

 

PostService

여기서도 의존성 주입 받은 JpaRepository 구현체를 이용할것이다.

우선 별 다른 조건 없이 DB 에 저장된 모든 Post 를 가져오는 findAll() 메서드를 이용한다.

기본적으로 findAll() 메서드는 List<Post> 형태로 Post 를 반환한다.

List<Post> posts = postRepository.findAll();

 

자바 8부터 지원하는 stream API 를 이용해서 List<Post> 형태로 오는 Post 를 PostResponse 로 변환하자.

public List<PostResponse> getList() {
    return postRepository.findAll().stream()
        .map(post -> PostResponse.builder()
            .id(post.getId())
            .title(post.getTitle())
            .content(post.getContent())
            .build())
        .collect(Collectors.toList());
}

 


PostServiceTest

게시글을 두개 넣었을 때 서비스에서 getList() 메서드를 호출하면 Post 2개 응답으로 내려오는지 확인하는 테스트이다.

@DisplayName("글 여러개 조회")
@Test
void getList() {
    // given
    Post post1 = Post.builder()
        .title("우리 이쁜 미카공주님")
        .content("우리 공주님")
        .build();
    Post post2 = Post.builder()
        .title("짤녀 공주면 자러감")
        .content("잘 자")
        .build();

    postRepository.save(post1);
    postRepository.save(post2);

    // when
    List<PostResponse> posts = postService.getList();

    // then
    assertEquals(2L, posts.size());
}

 

테스트는 우리가 원하는대로 동작하며 테스트가 성공함을 알 수 있다.

 


PostControllerTest

JSON 응답을 위처럼 List<PostResponse> 의 형태로 내려주기 때문에 기존의 jsonPath 형태를 바꿔서 테스트를 해야한다.

@DisplayName("글 여러개 조회")
@Test
void getList() throws Exception {
    // given
    Post post1 = Post.builder()
        .title("우리 이쁜 미카공주님")
        .content("우리 공주님")
        .build();
    Post post2 = Post.builder()
        .title("짤녀 공주면 자러감")
        .content("잘 자")
        .build();

    postRepository.save(post1);
    postRepository.save(post2);

    // expected
    mockMvc.perform(
            MockMvcRequestBuilders.get("/posts")
                .contentType(APPLICATION_JSON)
        )
        .andExpect(status().isOk())
        .andExpect(jsonPath("$.length()", is(2)))
        .andExpect(jsonPath("$[0].id").value(post1.getId()))
        .andExpect(jsonPath("$[0].title").value("우리 이쁜 미카공주님"))
        .andExpect(jsonPath("$[0].content").value("우리 공주님"))
        .andExpect(jsonPath("$[1].id").value(post2.getId()))
        .andExpect(jsonPath("$[1].title").value("짤녀 공주면 자러감"))
        .andExpect(jsonPath("$[1].content").value("잘 자"))
        .andDo(print());
}

ㄴ jsonPath("$.length()") 

Json 응답으로 내려온 리스트의 길이를 확인하는 메서드

ㄴ org.hamcrest.Matchers.is

위 메서드를 사용할 때 jsonPath("S.length()", is(2)) 부분에서 사용한 메서드이다.

다른 검증문에서 사용한 value 와 간단한 비교 시에는 비슷한 동작을 하지만 Matchers.is() 메서드를 사용 시 복잡한 데이터 비교시에 이 라이브러리에 내장된 더 많은 기능을 사용할 수 있다.

 jsonPath("$[0]")

Json 응답으로 내려온 리스트에서 0번째 인덱스의 Object 의 값을 의미한다.

위의 테스트처럼 jsonPath("$[0].id") 와 같은 형태로 사용한다.

 

 

테스트 수행 시 우리가 원하는대로 동작하며 테스트가 성공함을 알 수 있다.

 


리팩토링

PostResponse

기존처럼 Post 를 stream 으로 바꾸는것도 좋은 방법이지만  앞으로도 Post 를 PostResponse 로 바꿀 일이 많을 것이다.

매번 이렇게 스트림을 쓰고 각 필드별로 입력하려면 코드 양이 너무 많아진다. 

아래처럼 PostResponse 에서 Post 객체를 받는 생성자를 만드는 식으로 리팩토링 해서 코드 양을 줄여보자.

@Getter
public class PostResponse {

    private final long id;
    private final String title;
    private final String content;

    public PostResponse(Post post) {
        this.id = post.getId();
        this.title = post.getTitle();
        this.content = post.getContent();
    }

    @Builder
    public PostResponse(long id, String title, String content) {
        this.id = id;
        this.title = title.substring(0, Math.min(title.length(), 12));
        this.content = content;
    }
}

 

PostService

public List<PostResponse> getListAsc(int page) {
    return postRepository.findAll().stream()
        .map(post -> new PostResponse(post))
        .collect(Collectors.toList());
}

 

결과는 똑같지만 코드 양은 훨씬 줄어들었다.

앞으로 이런 Post -> PostResponse 로 전환하는 메서드가 많아질수록 줄어들 코드 양은 훨씬 많아질 것이다.

+ Recent posts