본문 바로가기

Backend

Springboot (2) 단위 테스트

1. 스프링 부트

스프링 부트는 내장 WAS를 사용한다. 이는 별도의 WAS를 사용 할 경우 발생하는 관리 및 작업 부담, 각 WAS 별 세부 설정 등의 업무 부담을 줄일 수 있다. 대규모 트래픽을 수용하는 실제 프로덕션 환경에서도 사용된다고 하니 성능 관련 이슈는 없다고 볼 수 있다.

 

2. 단위 테스트

사전에 작성 된 테스트 코드를 통해 기능을 검증한다. 불필요한 디버깅 코드 작성, WAS 실행/중지 행위를 최소화 하여 보다 효율적인 테스트/개발을 수행한다. 또한 잘 작성 된 테스트 코드는 변경 영향도를 파악하는 훌륭한 도구이자 문서가 된다.

 

3. xUnit 도구

- Java: Junit
- DB: DBUnit
- C++: CppUnit
- .net: NUnit

xUnit은 각종 단위 테스트 도구를 의미한다. 이 중 JUnit에 대해 학습 해 보았다.

 

4. Lombok 설치

build.gradle에 Lombok 라이브러리 의존성 추가

...
dependencies {
    compile('org.projectlombok:lombok')
    ...
}

 

Plugins 메뉴에서 Lombok → Install & Restart IDE

Settings 메뉴에서 Annotation Processors → Enable annotation processing

 

 

5. 테스트 코드 작성

[메인 클래스]

package com.wrallee.book.springboot;

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);
    }
}

*@SpringBootApplication 어노테이션에 의해 위 클래스가 메인 클래스가 된다. SpringBoot는 해당 어노테이션이 있는 위치부터 빈, 설정값 등을 읽기 때문에 메인 클래스는 항상 최 상단에 위치시켜야 한다.

 

[HomeController]

package com.wrallee.book.springboot.web;

import com.wrallee.book.springboot.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);
    }

}

 

[HomeControllerTest]

package com.wrallee.book.springboot.web;

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.*;


@RunWith(SpringRunner.class)
@WebMvcTest(controllers = HelloController.class)
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));
    }

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

*import static 키워드를 통해 클래스 정적 메소드를 임포트할 수 있다. 몰랐는데 jdk1.5부터 지원하고 있었다.
*org.hamcrest.Matcher.is 자동 임포트가 잘 안되어서 직접 적어줬다. IDE에서 Matcher 라이브러리 자동완성 지원이 약하다고 한다.
*assertJ의 assertThat이 JUnit의 assertThat보다 편리하다고 한다. 자세한 내용은 나중에 찾아볼 것

 

6. Gradle 버전 변경

테스트 진행 중 다음과 같은 오류가 발생할 수 있다.

...\HelloResponseDto.java:9: error: variable name not initialized in the default constructor

 

책에 해당 내용 관련 가이드를 따라가 보면 gradle 버전에 따른 롬복 설정 변화로 해당 문제가 발생했다고 한다. 터미널을 열어(Alt+F12) 다음 명령어로 gradle 버전을 변경한다.

> gradlew wrapper --gradle-version 4.10.2

...

BUILD SUCCESSFUL in 0s
1 actionable task: 1 executed

 

> gradlew --version
Downloading https://services.gradle.org/distributions/gradle-4.10.2-bin.zip

...

------------------------------------------------------------
Gradle 4.10.2
------------------------------------------------------------

Build time:   2018-09-19 18:10:15 UTC
Revision:     b4d8d5d170bb4ba516e88d7fe5647e2323d791dd

Kotlin DSL:   1.0-rc-6
Kotlin:       1.2.61
Groovy:       2.4.15
Ant:          Apache Ant(TM) version 1.9.11 compiled on March 23 2018
JVM:          1.8.0_242 ( 25.242-b08)
OS:           Windows Server 2019 10.0 amd64

 

7. 기타

[기타 어노테이션]

Annotation Description
@RestController Json을 반환하는 Rest 컨트롤러로 정의한다.
@GetMapping("/...") 요청 url을 지정한다.
@WebMvcTest(controllers = ...) WebMVC 테스트임을 명시한다. Controller 테스트시에만 적용 가능
@RequestParam("...") 넘어온 변수명에 해당하는 값을 함수 파라미터에 매핑한다.
JUnit / @RunWith(SpringRunner.class) JUnit 실행자를 지정한다. 스프링부트와 JUnit을 연결하는 역할
Lombok / @Getter get 메소드를 자동 생성한다.
Lombok / @RequiredArgsConstructor final로 정의 된 변수들로 구성 된 생성자를 자동 생성한다.

 

[IntelliJ 단축키]

기능 단축키
새 파일 Alt+Insert
자동 임포트 Alt+Enter
도구 검색 Ctrl+Shift+A
터미널 실행 Alt+F12
Live Templates / 메인 함수 psvm
Live Templates / 시스템 출력 sout