조앤의 기술블로그

[스프링부트] 02장. 스프링 부트에서 테스트 코드를 작성하자 본문

Study/Spring

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

쬬앤 2022. 1. 9. 15:49

테스트코드

새로운 기능이 추가될 때, 기존 기능이 잘 작동되는 것을 보장해준다. 

 

테스트코드 작성을 도와주는 프레임워크

자바용 - JUnit

많은 회사에서 JUnit4 버전을 주로 사용한다. 

 

2.2 Hello Controller 테스트 코드 작성하기 

- 일반적으로 패키지명은 웹사이트 주소의 역순으로 한다. (admin.swycha.com -> com.swycha.admin)

HelloController 클래스 코드 작성

package com.yjcha.admin.springboot.web;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;


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

* 에러

Cannot resolve method 'run' in 'SpringBootApplication'

* 에러 해결

오타..^_^

SpringBootApplication 이 아니라 SpringApplication 이었다.

 

* 설명

- Application 클래스는 앞으로 만들 프로젝트의 '메인 클래스'

- @SpringBootApplication 으로 인해 스프링 부트의 자동 설정, 스프링 Bean 읽기와 생성을 모두 자동으로 설정.

- 특히 @SpringBootApplication이 있는 위치부터 설정을 읽어가기 때문에 이 클래스는 항상 프로젝트의 최상단에 위치해야 한다. 

 

내장 WAS 사용하는 것을 권장하는 이유

-> 언제 어디서나 같은 환경에서 스프링부트를 배포할 수 있기 때문이다. 

 

테스트를 위한 Controller 작성

현재 패키지의 하위에 web이란 패키지를 생성. (앞으로 컨트롤러 관련 클래스는 모두 이 패키지에)

HelloController 작성  (간단한 API 생성)

package com.yjcha.admin.springboot.web.web;

import com.yjcha.admin.springboot.web.web.dto.HelloResponseDto;
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 HelloResponseDto helloDto(@RequestParam("name") String name, @RequestParam("amount") int amount) {
        return new HelloResponseDto(name, amount);
    }
}

* 설명

1. @RestController

- 컨트롤러를 JSON을 반환하는 컨트롤러로 만들어줌.

- 예전에는 @ResponseBody를 각 메소드마다 선언했던 것을 한번에 사용할 수 있게 해주는 것.

(@ResponseBody는 많이 써봤다..!)

 

2. @GetMapping

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

- 예전에는 @ResquestMapping(method = RequestMethod.GET)으로 사용되었다. -> 이거 많이 써봄..

- 따라서 이제 이 프로젝트는 /hello 로 요청이 오면 문자열 hello를 반환하는 기능을 가지게 되는 것.

 

이제 WAS 실행대신, 테스트코드로 검증해보기!

src/test/java 디렉토리에

앞에서 생성했던 패키지를 그대로 다시 생성한다!

(여기서 좀 헷갈렸음, 디렉토리랑 패키지 위치 때문에)

** 원칙

@SpingBootApplicatino 어노테이션이 붙은 클래스가 존재하는 패키지의

하위 패키지에 테스트를 둬야 한다.

 

또한 일반적으로 테스트클래스는 대상 클래스 이름에 Test를 붙인다. (HelloController -> HelloControllerTest)

(테스트코드는 진짜 생소해서 어노테이션과 작성방법이 진짜 생소했다..)

 

HelloControllerTest 작성

package com.yjcha.admin.springboot.web;

import com.yjcha.admin.springboot.web.web.HelloController;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.autoconfigure.web.servlet.WebMvcTest;
import org.springframework.test.context.junit4.SpringRunner;
import org.springframework.test.web.servlet.MockMvc;

import static org.hamcrest.Matchers.is;
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.content;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.jsonPath;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;

@RunWith(SpringRunner.class) // 1.
@WebMvcTest(controllers = HelloController.class) // 2.
public class HelloControllerTest {

    @Autowired // 3.
    private MockMvc mvc; // 4.

    @Test
    public void hello가_리턴된다구() throws Exception {
        String hello = "hello";

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

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

* 설명

1. @RunWith(SpringRunner.class)

- 테스트를 진행할 때 JUnit에 내장된 실행자 외에 다른 실행자를 실행시킨다.

- 여기서는 SpringRunner이라는 스프링 실행자를 사용한다.

- 즉, 스프링부트 테스트와 JUnit 사이에 연결자 역할을 한다.

 

2. @WebMvcTest

- 여러 스프링 테스트 어노테이션 중, Web(Spring MVC)에 집중할 수 있는 어노테이션.

- 선언할 경우 @Controller, @ControllerAdvice 등을 사용할 수 있다.

- 단, @Service, @Component, @Repository 등은 사용할 수 없다.

- 여기서는 컨트롤러만 사용하기 때문에 선언한다.

 

3. @Autowired

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

 

4. private MocMvc mvc

- 웹 API를 테스트할 때 사용한다.

- 스프링 MVC 테스트의 시작점이다.

- 이 클래스를 통해 HTTP GET, POST 등에 대한 API 테스트를 할 수 있다. 

 

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

- MockMvc를 통해 /hello 주소로 HTTP GET 요청을 한다.

- 체이닝이 지원되어 아래와 같이 여러 검증 기능을 이어서 선언할 수 있다.

 

6. .andExpect(status().isOk())

- mvc.perform의 결과를 검증한다.

- HTTP Header의 Status를 검증한다.

- 우리가 흔히 알고 있는 200, 404, 500 등의 상태를 검증한다.

- 여기선 OK, 즉 200인지 아닌지를 검증한다.

 

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

- mvc.perform의 결과를 검증한다.

- 응답 본문의 내용을 검증한다.

- Controller에서 "hello"를 리턴하기 때문에 이 값이 맞는지 검증한다.