본문 바로가기
springboot로 API만들어보기

[스프링부트로 API 만들기] Junit 으로 API 테스트 코드 작성하기

by alwaysone 2021. 1. 5.

지금까지 간단하게 API를 구현해보았다. 이제부터는 기능 구현만큼이나 중요한 테스트 코드를 작성해보자

테스트 코드

테스트 코드는 작성한 소프트웨어가 의도한 대로 작동하는지 확인해보는 코드이다. 기존에는 테스트 계획을 세워 수동으로 하였으나 최근에는 테스트 코드를 작성하여 검증을 하는 추세이다. 

테스트 코드가 잘 짜여 있으면, 클라이언트 쪽에 서버의 동작이 완벽하다고 보장을 할 수 있음과 동시에 코드의 수정이 있었을 때 일어나는 좋지 않은 side-effect를 빠르게 확인할 수 있다. 또한 검증하는 과정에서 소프트웨어의 각 부분이 지켜야 하는 규칙을 정의하기 때문에 테스트 코드를 보고 빠르게 프로젝트를 파악할 수도 있다. 

고로 테스트코드는 선택이 아니라 필수이다. 자세한 내용은 이후에 따로 포스팅하겠다.

지켜야 하는 규칙

테스트 코드는 기능을 자동으로 테스트하는데도 의의가 있지만, 해당 코드가 어떻게 동작해야 하는지 길을 보여주는 것이기도 하다. 따라서 읽기 편하고, 냉정해야 한다.

  1. 쉽게 이해할 수 있도록 테스트 케이스 이름을 짓자.
  2. 한 테스트에서는 한 가지만 테스트하자
  3. 누구나 이해 가능하도록 최대한 쉽게 작성하자
  4. 프로그램이 수정되면 테스트 코드도 수정되도록 설계하자
  5. println을 사용해서 눈으로 확인하지 말고 코드가 검증하도록 하자
  6. 실패해야 하는 경우의 수도 전부 작성하자

작성해보기

테스트 코드를 작성할 때 공통적으로 작성해야 하는 부분을 따로 빼놓고 상속받아서 테스트를 작성하면 훨씬 편하다.

> common/BaseControllerTest.java

@Disabled
@Transactional
@SpringBootTest
@AutoConfigureMockMvc
public class BaseControllerTest {

  @Autowired
  protected MockMvc mockMvc;

  @Autowired
  protected ObjectMapper objectMapper;

}

- @SpringBootTest

통합테스트를 제공하는 어노테이션이다. 모든 Bean들을 로드해서 실제 구동되는 서버와 같게 콘텍스트를 로드하여 테스트하기 때문에 실제로 서버가 응답하는 결과를 확인해 볼 수 있다. 하지만 전부 로두하기때문에 느리다는 단점이 있다.

- @AutoConfigureMockMVC

요청을 테스트할때 사용되는 mockMVC를 자동으로 설정해주는 어노테이션이다. 

- ObjectMapper 

객체를 json으로 변환하거나 그 반대에 사용한다. 여기서는 객체를 json문자열로 바꿔서 body에 실어 보내는 데 사용된다.

 

여기서는 한 기능을 예시로 테스트 코드를 작성해보겠다. 나머지 API들에 대한 테스트는 따로 작성해보길 바란다.

테스트 코드는 보통 Given When Then 이렇게 세 가지로 나눠서 작성한다.

- Given

테스트를 위해 데이터들을 준비하는 과정이다.

- When

실제로 요청을 하거나 실행을 해보는 과정이다.

- Then

실행한 결과를 검증하는 과정이다. 

> post/AddPostTest.java

@DisplayName("포스트 저장 테스트")
public class AddPostTest extends BaseControllerTest {


    @Test
    @DisplayName("포스트 저장(성공)")
    void insertPostSuccess() throws Exception {
        // Given
        UpdatePostRequest updatePostRequest = new UpdatePostRequest("title", "body");
        // When
        ResultActions resultActions = this.mockMvc.perform(post("/posts/")
                .contentType(MediaType.APPLICATION_JSON)
                .content(this.objectMapper.writeValueAsString(updatePostRequest))
        );
        // Then
        resultActions.andExpect(status().isCreated())
                .andExpect(jsonPath("title").value("title"))
                .andExpect(jsonPath("body").value("body"))
                .andExpect(jsonPath("views").value(0))
        ;
    }


    @Test
    @DisplayName("포스트 저장(실패) - 잘못된 body")
    void insertPostFailBecauseContentIsNull() throws Exception {
        // Given
        UpdatePostRequest updatePostRequest = new UpdatePostRequest("title", null);
        // When
        ResultActions resultActions = this.mockMvc.perform(post("/posts/")
                .contentType(MediaType.APPLICATION_JSON)
                .content(this.objectMapper.writeValueAsString(updatePostRequest))
        );
        // Then
        resultActions.andExpect(status().isInternalServerError())
        ;
    }
}

- @DisplayName

테스트가 실행될 때, 테스트 명에 표시될 이름을 적는곳이다. 하지만 gradle을 통해 테스트를 했을 땐 메서드명이 보인다.

- @Test

이 메소드가 테스트 코드임을 알리는 어노테이션이다.

현재까지의 패키지 구조

마무리

지금까지 테스트 코드를 사용해 API가 의도대로 잘 동작하는지 확인해 보았다. 다음 시간엔 이 테스트를 기반으로 사람들이 사용할 수 있도록 문서를 작성해보도록 하자

댓글