SpringBoot TestCode

유재훈·2023년 5월 18일
0

Spring_Study

목록 보기
8/9

  • Red : 항상 실패하는 테스트를 먼저 작성
  • Green : 테스트가 통과하는 프로덕션 코드 작성
  • Refactor : 테스트가 통과하면 프로덕션 코드 리팩토링

Test Code

Test CodeTDD는 다른 의미이다.

  • TDD : 테스트가 주도하는 개발이며 테스트 코드를 먼저 작성
  • Test Code : TDD의 첫번째 단계인 기능 단위의 테스트 코드를 작성

Test Code를 작성해야 하는 이유

먼저 전에 프로젝트를 진행하며 아래와 같은 순서에서 2~5번을 계속 반복해왔다. 반복을 계속하니 시간이 많이 걸리게 되었다.

1. 코드를 작성
2. 프로그램(Tomcat) 실행
3. Postman과 같은 API 테스트 도구로 HTTP 요청
4. 요청결과를 System.out.println으로 검증
5. 결과가 다르면 다시 프로그램(tomcat)을 중지하고 코드를 수정

Test Code를 작성해야 하는 이유는 다음과 같다.

  • 개발단계 초기에 문제를 발견하게 도와줌
  • 개발자가 나중에 코드를 리팩토링하거나 라이브러리 업그레이드 등에서 기존 기능이 올바르게 작동하는지 확인 가능
  • 기능에 대한 불확실성을 감소
  • 시스템에 대한 실제 문서를 제공. 즉, 단위 테스트 자체가 문서로 사용

결국톰캣을 내렸다가 다시 실행시키는 시간 절약,눈으로 검증하지 않게 자동검증 가능, 개발자가 만든 기능을 안전하게 보호, 기존 기능이 잘 작동되는 것을 보장해준다.

테스트 코드 작성은 다음과 같다

기존 코드

HelloController

package com.sh.movie.testcode;

import com.sh.movie.testcode.dto.HelloDto;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;

@RestController
public class HelloController {

    @GetMapping("/hello")
    public String hello(){
        return "hello";
    }

    @GetMapping("/hello/dto")
    public HelloDto helloDto(@RequestParam("name") String name, @RequestParam("amount") int amount){
        return new HelloDto(name,amount);
    }
}

HelloDto

package com.sh.movie.testcode.dto;

import lombok.Getter;
import lombok.RequiredArgsConstructor;

@Getter
@RequiredArgsConstructor
public class HelloDto {
    private final String name;
    private final int amount;
}

테스트 코드

HelloControllerTest

package com.sh.movie.testcode;

import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.autoconfigure.web.servlet.WebMvcTest;
import org.springframework.test.context.junit.jupiter.SpringExtension;
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.*;
import static org.hamcrest.Matchers.is;


@ExtendWith(SpringExtension.class)
@WebMvcTest(controllers = HelloController.class)
public class HelloControllerTest {

    @Autowired
    private MockMvc mvc;

    @Test
    public void helloReturn() throws Exception{
        String hello = "hello";

        mvc.perform(get("/hello"))
                .andExpect(status().isOk())
                .andExpect(content().string(hello));
    }

    @Test
    public void helloDtoReturn() throws Exception{
        String name = "hello";
        int amount = 1000;

        mvc.perform(
                get("/hello/dto")
                        .param("name",name)
                        .param("amount",String.valueOf(amount)))
                .andExpect(status().isOk())
                .andExpect(jsonPath("$.name",is(name)))
                .andExpect(jsonPath("$.amount",is(amount)));
    }
}

HelloDtoTest

package com.sh.movie.testcode.dto;

import org.junit.jupiter.api.Test;

import static org.assertj.core.api.Assertions.assertThat;

public class HelloDtoTest {

    @Test
    public void lombokTest(){
        String name = "test";
        int amount = 1000;

        HelloDto dto = new HelloDto(name,amount);

        assertThat(dto.getName()).isEqualTo(name);
        assertThat(dto.getAmount()).isEqualTo(amount);
    }
}

실행했을 시 녹색체크표시가 뜨면 정상동작된것이다.

@RestController

  • Controller를 JSON을 반환하는 Controller로 만들어 줌
  • 예전에는 @ResponseBody를 각 메소드마다 선언했던 것을 한번에 사용해줌

@RequiredArgsConstructor

  • 선언된 모든 final 필드가 포함된 생성자를 생성
  • final이 없는 필드는 생성자에 미포함

@ExtendWith(SpringExtension.class)

  • 테스트를 진행할 때 JUnit5에 내장된 실행자 외에 다른 실행자를 실행
    (JUnit4 : RunWith(SpringRunner.class))
  • 스프링 부트 테스트와 JUnit 사이에 연결자 역할

@WebMvcTest

  • 여러 스프링 테스트 어노테이션 중, Web(Spring Mvc)에 집중할 수 있는 어노테이션
  • 선언할 경우 @Controller, @ControllerAdvice 등을 사용 가능
  • 단, @Service, @Component, @Repository 등은 사용 불가

private MockMvc mvc

  • 웹 API 테스트 할 때 사용
  • 스프링 MVC 테스트의 시작점
  • 이 클래스를 통해 HTTP GET, POST 등에 대한 API 테스트 가능

mvc.perform(get("/hello"))

  • MockMvc를 통해 /hello 주소로 HTTP GET 요청
  • 체이닝이 지원되어 아래와 같이 여러 검증 기능 선언 가능

.andExpect(status.isOk())

  • HTTP Header의 Status 검증
  • 200, 400, 500등의 상태 검증
  • OK는 즉 200인지 아닌지 검증

.andExpect(content().string(hello))

  • 응답 본문의 내용 검증
  • Controller에서 "hello"를 리턴하기에 값이 맞는지 검증

@JsonPath

  • JSON 응답값을 필드별로 검증할 수 있는 메소드
  • $를 기준으로 필드명 명시

assertThat

  • assertj라는 테스트 검증 라이브러리의 검증 메소드
  • 검증하고 싶은 대상을 메소드 인자로 받음
  • 메소드 체이닝이 지원되어 isEqualTo와 같이 메소드를 이어받음

isEqualTo

  • assertj의 동등비교 메소드
  • assertThat에 있는 값과 isEqualTo의 값을 비교해서 같을 때 성공

느낀점

이때까지 테스트코드를 작성하지 않고 프로젝트를 진행했다. 그러다 보니 톰캣을 내렸다 다시 실행하는 일이 너무 많았으며 굳이 테스트 코드를 작성해야하나라는 생각을 가지고 있었다. 하지만 테스트 코드에 중요성을 알았기에 테스트 코드 습관을 길러야겠다.

0개의 댓글