상똥이의 Back-End 공부방

[Board Project] 13. 뷰 엔드포인트 테스트 정의 본문

프로젝트/게시판 만들기

[Board Project] 13. 뷰 엔드포인트 테스트 정의

상똥백 2023. 10. 23. 23:21

[0. 준비단계]

1. 프론트엔드 서버사이드 기술 - 타임리프 템플릿 엔진

- spring initializr에서 타임리프 의존성 추가

 

2. 컨트롤러 생성

(0) 루트패키지에서 controller 패키지 생성

(1) ArticleComtroller.class 생성

- @Controller : 스테레오 타입 애노테이션 / 뷰를 주로 담을 거라

- @RequestMapping : 매핑 디자인 가능 / 경로 설정(/articles)으로 아래의 핸들러 메소드들의 경로 감소

- command-shift-t : 새 테스트 생성

 

[1. 클래스 생성]

1. 컨트롤러 클래스 생성

- root 페이지 아래에 controller.package 생성

- 생성한 패키지 안에 ArticleController.class 생성

 

2. 어노테이션 삽입

- @RequestMapping("/articles") : URL을 미리 articles로 설정해서 경로를 줄일 수 있음

- @Controller : 클라이언트의 요청을 처리하고 응담을 생성해 반환 / @RequestMapping과 사용하면 특정 URL경로와 HTTP 메소드를 연결할 수 있음

 

3. @GetMapping

- public String articles()

- return "articles/index"

코드 (접은 글)

더보기
package com.fastcampus.projectboard.controller;

import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;

@RequestMapping("/articles")
@Controller
public class ArticleController {
    @GetMapping
    public String articles(){
        return "articles/index";
    }
}

 

[2. 테스트 생성]

1. ArticleControllerTest.java

(1) @DisplayName("view 컨트롤러 - 게시글")

(2) @WebMvcTest(ArticleController.class) : ArticleController.class

- 생성자 주입 방식으로 접근 (생성자가 하나만 있을 때 파라미터 옆에 @Autowired를 생략할 수 없음)

코드 (접은 글) 

더보기
package com.fastcampus.projectboard.controller;

import org.junit.jupiter.api.DisplayName;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.autoconfigure.web.servlet.WebMvcTest;
import org.springframework.test.web.servlet.MockMvc;

@DisplayName("view controller - 게시글")
@WebMvcTest("ArticleController.class")
class ArticleControllerTest {
	
    private final MockMvc mvc;
    public ArticleComtrollerTest(@Autowired MockMvc mvc){
    	this.mvc = mvc;
    }
    
}

 

2. 테스트

(1) perform

- 컨트롤러 메소드를 호출해 응답을 검증하는 데 사용

- HTTP요청 수행

- get → command(ctrl)+spacebar로 MockMvcRequestBuilders.get 선택(그냥 코드 짧아지라고) → option(alt)+enter로 import statically(관련 클래스를 위에 호출하고 코드를 간결하게)

- option+enter : exeption 처리

- get("/articles") : 게시판 가져오기

(3) andExpect(status().isOk()) : 서버 연결(200)확인

(4) andExpect(content().contentTypeCompatibleWith(MediaType.TEXT_HTML))

- 호출한 내용이 HTML인지 확인

- 그냥 contentType만쓰면 호환되는 것들이 포함되지 않음

(5) andExpect(view().name("articles/index")) : 실제로 매핑될 마크업 파일의 이름을 비교

(6) andExpect(model().attributesExists("articles")) : 생성한 모델 데이터에서 게시글들이 있는지 확인

(7) 단일 게시글 조회의 경우, 댓글이 0개 이상 나와야 함

(8) 당장 웹을 구현하지 않았으므로, index.html이 만들어질때까지 각각 @Disabled처리 해준다.

더보기
package com.fastcampus.projectboard.controller;

import org.junit.jupiter.api.Disabled;
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.web.servlet.WebMvcTest;
import org.springframework.http.MediaType;
import org.springframework.test.web.servlet.MockMvc;

import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.*;

@DisplayName("view controller - 게시글")
@WebMvcTest(ArticleController.class)
class ArticleControllerTest {
    private final MockMvc mvc;

    public ArticleControllerTest(@Autowired MockMvc mvc) {
        this.mvc = mvc;
    }


    @DisplayName("[view] [Get] 게시판 페이지 - 정상 호출 ")
    @Test
    public void givenNothing_whenRequestingArticlesView_thenReturnsArticlesView() throws Exception {
        //given

        //when & then
        mvc.perform(get("/articles"))
                .andExpect(status().isOk())
                .andExpect(content().contentTypeCompatibleWith(MediaType.TEXT_HTML))
                .andExpect(view().name("articles/index"))
                .andExpect(model().attributeExists("articles"));
    }

    @Disabled
    @DisplayName("[view] [Get] 게시글 단일 페이지 - 정상 호출")
    @Test
    public void givenNothing_whenRequestingArticleView_thenReturnsArticleView() throws Exception {
        //given

        //when & then
        mvc.perform(get("/templates/articles/1"))
                .andExpect(status().isOk())
                .andExpect(content().contentType(MediaType.TEXT_HTML))
                .andExpect(view().name("article/detail"))
                .andExpect(model().attributeExists("article"))
                .andExpect(model().attributeExists("articleComments"));
    }

    @Disabled
    @DisplayName("[view] [Get] 게시글 검색 페이지 - 정상 호출")
    @Test
    public void givenNothing_whenRequestingArticleSearchView_thenReturnsArticleSearchView() throws Exception {
        //given

        //when & then
        mvc.perform(get("/templates/articles/search"))
                .andExpect(status().isOk())
                .andExpect(content().contentType(MediaType.TEXT_HTML))
                .andExpect(view().name("articles/search"));
    }

    @Disabled
    @DisplayName("[view] [Get] 게시글 해시태그 검색 페이지 - 정상 호출")
    @Test
    public void givenNothing_whenRequestingArticleHashtagSearchView_thenReturnsArticleHashtagSearchView() throws Exception {
        //given

        //when & then
        mvc.perform(get("/templates/articles"))
                .andExpect(status().isOk())
                .andExpect(content().contentType(MediaType.TEXT_HTML))
                .andExpect(view().name("articles/search-hashtag"));
    }
}