[2장] 스프링 부트에서 테스트 코드를 작성하자

미천한 개발중생·2023년 9월 12일
0

2장에서는 테스트코드의 중요성과 작성방법을 알려주고 있습니다.

테스트 코드의 이점

  • 개발단계 초기에 문제를 발견하게 도와줍니다.

  • 개발자가 코드를 리팩토링 하거나 라이브러리 업그레이드 등에서 기존 기능이 올바르게 작동하는지 확인
    할 수 있습니다.(ex.회귀테스트)

  • 기능에 대한 불확실성을 감소시킬 수 있습니다.

    테스트 코드 작성을 도와주는 프레임워크는 대중적으로 xUnit을 사용합니다. 이 책에서는 자바용인 JUnit을 사용하였습니다. 지난 게시물에 설명했지만 코드를 최신화하여 책에서 사용하는 JUnit4가 아닌 Junit5를 사용합니다.

메인클래스 작성

@SpringBootApplication
public class Application {
    public static void main(String[] args) {
        SpringApplication.run(Application.class, args);
    }
}

WAS

Web Application Server, 웹 어플리케이션 서버의 약자로 메인 메서드의 SpringApplication.run으로 내장 WAS를 실행합니다. 여기서 내장 WAS란 별도로 외부에 WAS를 두지 않고 애플리케이션을 실행할 때 내부에서 WAS를 실행하는 것을 이야기합니다. 이렇게 되면 항상 서버에 톰캣을 설치할 필요가 없습니다.

내장 WAS를 사용하여 얻는 이점

내장 WAS를 사용해서 얻는 이점은 언제 어디서나 같은 환경에서 스프링 부트를 배포 할 수 있다는 것입니다. 스프링부트는 내장 WAS사용을 권장합니다.


@SpringBootApplication

@SpringBootApplication 어노테이션으로 인해 스프링 부트의 자동 설정, 스프링 Bean 읽기와 생성을 모두 자동으로 설정됩니다.
이 어노테이션이 있는 위치부터 설정을 읽어가기 때문에 메인 클래스는 항상 프로젝트 최상단에 위치해야 합니다.

HomeController 작성

@RestController
public class HelloController {
    @GetMapping("/hello")
    public String Hello() {
        return "hello";
    }    
}

@RestController

컨트롤러를 JSON을 반환하는 컨트롤러로 만들어 줍니다.

@GetMapping

HTTP Method인 Get의 요청을 받을 수 있는 API를 만들어 줍니다.

### HomeController 테스트

일반적으로 테스트 클래스는 대상 클래스 이름 뒤에 Test를 붙인다고 합니다. ex) HomeControllerTest

@ExtendWith(SpringExtension.class)
@WebMvcTest
public class HelloControllerTest {
    @Autowired
    private MockMvc mvc;

    @Test
    public void return_hello() throws Exception {
        String hello = "hello";
        mvc.perform(get("/hello"))
                	.andExpect(status().isOk())
                	.andExpect(content().string(hello));
    }
}

@ExtendWith

@RunWith 어노테이션의 경우 Junit5가 되면서 @ExtendWith으로 변경되었습니다. 테스트를 진행할 때, 스프링 부트 테스트와 JUnit의 연결자 역할을 합니다. 책에서는 SpringRunner라는 스프링 실행자를 사용하였으나, JUnit5를 사용하면서 SpringRunner 도 마찬가지로 SpringExtension으로 변경되었습니다.

@WebMvcTest

스프링 어노테이션 중, Web(Spring MVC)에 집중할 수 있는 어노테이션 입니다. 선언할 경우 @Controller, ControllerAdvice 등 사용할 수 있습니다. @Service, @Component, Repository 등은 사용 불가합니다.

@Autowired

스프링이 관리하는 빈(Bean)을 주입받습니다.

private MockMvc mvc

웹 API를 테스트할 때 사용합니다. 스프링 MVC테스트의 시작점입니다. 이 클래스를 통해 HTTP GET, POST 등에 대한 API테스트를 할 수 있습니다.

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

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

.andExpect(status().isOk())

mvc.perform의 결과를 검증합니다. HTTP Header Status를 검증합니다. ex)200, 404, 500등의 상태

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

응답 본문의 내용을 검증합니다. Controller에서 "hello"를 리턴하기 때문에 이 값이 맞는지 검증합니다.


Lombok(롬복)사용하기

롬복은 자바로 개발할 때 자주 사용하는 Getter, Setter, 기본 생성자, toString 등을 어노테이션으로 자동 생성해줍니다.

DTO생성

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

@Getter

선언된 모든 필드의 get 메서드를 생성해줍니다.

@RequiredArgsConstructor

선언된 모든 final 필드가 포함된 생성자를 생성해줍니다(final이 없는 필드는 생성자에 포함x).

DTO 테스트

public class HelloResponseDtoTest {

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

        //when
        HelloResponseDto dto = new HelloResponseDto(name, amount);

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

}

@assertThat

assertj라는 테스트 검증 라이브러리의 검증 메서드입니다. 검증하고 싶은 대상을 메서드 인자로 받습니다. 메서드 체이닝이 지원되어 isEqualTo와 같이 메서드를 이어서 붙일 수 있습니다.

@isEqualTo

assertj의 동등 비교 메서드입니다. assertThat에 있는 값과 isEqualTo에 있는 값을 비교해서 같을 때만 성공합니다.

assertj의 장점

  • CoreMatchers와 달리 추가적으로 라이브러리가 필요하지 않습니다.
  • 자동완성이 좀 더 확실하게 지원됩니다.

HomeController에서 DTO사용

HomeController 클래스에 다음 코드를 추가합니다.

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

@RequestParam

외부에서 API로 넘긴 파라미터를 가져오는 어노테이션입니다.


HomeControllerTest에서 DTO테스트

HomeControllerTest 클래스에 다음 코드를 추가합니다.

@Test
    public void return_HelloDto() 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)));


    }

.param

API 테스트시 사용될 요청 파라미터를 설정(단, 값은 String만 허용) 합니다. 그래서 숫자/날짜 등의 데이터도 등록할 때는 문자열로 변경해야만 가능합니다.

jsonPath

JSON 응답값을 필드별로 검증할 수 있는 메서드 $를 기준으로 필드명을 명시합니다.

profile
공부 목적의 블로그 입니다. 부족한 점이 많으니 잘못된 정보가 있다면 지적부탁드려요!

0개의 댓글