> For the complete documentation index, see [llms.txt](https://docs.sysout.co.kr/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://docs.sysout.co.kr/web/back-end/spring-boot/spring-boot-test.md).

# Spring Boot Test

Spring Boot에서 테스트를 수행하는 방법에 대해서 살펴본다

## TDD

TDD(Test Driven Development)란 고품질의 소프트웨어 기능을 구현하기 위하여 테스트를 수행하고 충분한 검토와 피드백을 통해 개선시켜나가는 개발 방법론을 말한다.&#x20;

## Spring Boot Test

Spring Boot에서는 테스트를 위한 별도의 src 공간이 배정되어 있으며 위치는 **src/test/java**이다. Spring Legacy와 다른점은 **src/test/resources**가 없다는 것이다. 해당 영역에서 테스트를 할 때 다음 기능을 사용할 수 있다.

* pom.xml에 \<scope>가 test로 설정된 의존성을 사용할 수 있다.
* test source는 빌드에서 제외된다
* test source에서는 main source를 사용할 수 있다

## 필요 의존성

Spring Boot에서는 프로젝트 생성 시 다음 의존성이 필수적으로 추가되어 있다.

* org.springframework.boot.spring-boot-starter-test

테스트에 필요한 각종 하위 의존성들을 자동으로 불러오므로 대부분의 테스트가 가능하다.

## JUnit

Spring Boot Test는 JUnit 5를 기반 기술로 사용한다. JUnit 5는 JUnit의 후속 버전으로 자바와 JVM을 기반으로 한 언어 및 프레임워크에서 사용할 수 있는 강력한 단위 테스트 도구이다.

{% embed url="<https://junit.org/junit5/>" %}

## 테스트 클래스 생성

테스트 클래스를 src/test/java에 생성한다. 생성 시 프로젝트에서 설정한 base package를 지켜야 한다.

```java
@SpringBootTest
public class TestClass {

    @Test
    public void testMethod(){
        
    }
    
}
```

테스트 클래스의 기본 형태이다. 사용된 Annotation은 다음과 같다.

* <mark style="color:red;">`@SpringBootTest`</mark> - 클래스에 설정하여 Spring Test를 위한 준비를 수행한다.
* <mark style="color:red;">`@Test`</mark> - JUnit 테스트 메소드임을 명시한다.

### @SpringBootTest

SpringBootTest에서 수행하는 세부 기능은 다음과 같다.

* ContextLoader 설정
  * 지정된 <mark style="color:red;">`@ContextConfiguration`</mark>이 없을 경우 SpringBootContextLoader 사용
* Configuration 탐색
  * 사용된 <mark style="color:red;">`@Configuration`</mark>이 없을 경우 <mark style="color:red;">`@SpringBootConfiguration`</mark>을 검색
* properties 속성 사용 설정
* args 속성 사용 설정
* 지정 혹은 랜덤 포트를 사용하여 웹 서버를 테스트할 수 있는 WebEnvironment 모드 설정

### @Test

JUnit 테스트 메소드임을 명시한다. 메소드 생성 시 주의할 사항은 다음과 같다.

* private 접근제한을 가질 수 없다
* static 메소드는 불가능하다
* void가 아닌 다른 반환형을 설정할 수 없다
* 이름은 자유롭게 설정할 수 있다

## 테스트 코드 작성

테스트를 하는 목적은 <mark style="color:red;">**가설에 대한 검증**</mark>을 하는 것이다. 따라서 다음과 같은 가설을 설정해야 한다.

* 가설 : `1.1` + `2.2` 는 `3.3` 과 같을 것이다.

가설 수립 후 가설에 따른 코드를 작성한다.

```java
@Test
public void testMethod(){
    double a = 1.1;
    double b = 2.2;
    double c = 3.3;
    assertEquals(a+b, c);
}
```

직접 `a + b == c` 라는 코드를 작성하여 결과를 확인해도 되지만 가설이 맞지 않을 경우 실패로 간주되어야 하므로 단정문(Assertion)을 사용하여 테스트 성공 조건을 작성한다. <mark style="color:red;">`static import`</mark>를 사용하여 구문을 간소화하였으며, 원 코드는 다음과 같다.

```java
@Test
public void testMethod(){
    double a = 1.1;
    double b = 2.2;
    double c = 3.3;a
    Assert.assertEquals(a+b, c);
}
```

## 테스트 실행 및 결과 확인

실행하면 테스트의 성공 실패 여부와 실행 시간이 측정되어 JUnit 탭에 출력된다.

{% hint style="info" %}
실행 시 **JUnit Test**를 선택해야 한다.
{% endhint %}

<figure><img src="https://4208234536-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F-M_TNZwLuHV9ipYLbvRq%2Fuploads%2FPHcbFl8hxm4zBvB2bJC2%2Fimage.png?alt=media&amp;token=48be0f02-3b09-4dcf-ace5-d0b9a00100d0" alt=""><figcaption></figcaption></figure>

## 단정문의 종류

사용 가능한 단정문의 종류는 여러 가지가 있으며, 자세한 설명은 다음 문서를 참고한다.

{% content-ref url="/pages/-MdH-5Fd-WtxBy7Oc2zU" %}
[Assert 단정문](/web/back-end/what-is-spring-framework/spring-test/assert.md)
{% endcontent-ref %}

## 모듈 테스트

<mark style="color:red;">`@Repository`</mark>, <mark style="color:red;">`@Component`</mark>, <mark style="color:red;">`@Service`</mark> 등 개발한 모듈을 주입하여 테스트 할 경우 <mark style="color:red;">`@SpringBootTest`</mark> 설정을 통해 Spring Boot 환경에서 설정한 내용들을 <mark style="color:red;">`@Autowired`</mark>로 주입하여 사용할 수 있다.

### 모듈 생성

다음과 같이 랜덤 문자열을 생성하는 도구를 만들었다고 가정한다.

```java
@Component
public class RandomGenerator {
    
    private final String alphabetLowercase = "abcdefghijklmnopqrstuvwxyz";
    private final String alphabetUppercase = "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
    private final String number = "0123456789";
    private Random r = new Random();
    
    public String alphabet(int size){
        StringBuffer range = new StringBuffer();
        range.append(alphabetLowercase);
        range.append(alphabetUppercase);
        
        Stringbuffer result = new StringBuffer();
        for(int i=0; i < size; i++){
            int index = r.nextInt(range.length());
            result.append(range.charAt(index));
        }
        return result.toString();
    }
}
```

### 테스트 생성

RandomGenerator를 테스트하기 위한 코드는 다음과 같다. 테스트 코드는 반드시 **src/test/java**에 생성해야 한다.

```java
@SpringBootTest
public class ModuleTest {
    @Autowired
    private RandomGenerator generator;
    
    @Test
    public void alphabetGenerateTest(){
        String str = generator.alphabet(10);
        System.out.println("str = " + str);
        
        assertEquals(str.length(), 10);
    }
}
```

<mark style="color:red;">`@Autowired`</mark>를 사용하여 <mark style="color:red;">`@Component`</mark>로 등록한 <mark style="color:blue;">`RandomGenerator`</mark> 클래스를 주입하여 테스트를 수행하고 있다. 따라서 해당 테스트가 성공했다면 프로젝트 내에서 <mark style="color:blue;">`RandomGeneartor`</mark> 클래스를 주입하여 사용하는 것에 문제가 없다는 것을 확신할 수 있다.

## 컨트롤러 테스트

컨트롤러를 테스트하기 위해서는 **Mock MVC** 설정이 이루어져야 한다. Spring Boot에서는 Spring Legacy와 다르게 자동화 설정을 지원한다.

Spring Legacy에 대한 내용은 다음 문서를 참고한다.

{% content-ref url="/pages/-MdH-Aq8vXyyXXrj8Jfs" %}
[MockMvc Test](/web/back-end/what-is-spring-framework/spring-test/mockmvc-test.md)
{% endcontent-ref %}

### 컨트롤러 생성

다음과 같이 요청을 처리할 수 있는 컨트롤러를 생성한다. View 는 사용하지 않는다.

```java
@Controller
public class DummyController {
    
    @Autowired
    private RandomGenerator generator;
    
    @GetMapping("/random-string")
    @ResponseBody
    public String randomString(){
        return generator.alphabet(10);
    } 
    
}
```

해당 컨트롤러의 정상 작동 여부를 테스트하려면 브라우저를 열고 주소를 입력하거나 Spring Boot Test를 사용할 수 있다.

### 테스트 생성

테스트 클래스를 통해 컨트롤러를 테스트하고 싶을 경우 추가적으로 <mark style="color:red;">`@AutoConfigureMockMvc`</mark> 애노테이션을 클래스에 설정해야 한다. 설정하면 자동으로 테스트가 가능한 <mark style="color:blue;">`MockMvc`</mark> 클래스의 객체를 등록해주며, 이를 주입하여 사용할 수 있다.

```java
@SpringBootTest
@AutoConfigureMockMvc
public class ControllerTest {
    
    @Autowired
    private MockMvc mockMvc;
    
    @Test
    public void requestTest(){
        mockMvc.perform(get("/generate-string"))
                .andExpect(status().is2xxSuccessful())
                .andDo(print())
                .andReturn();
    }
    
}
```

MockMvc에 대한 명령 설명은 다음 문서를 참조한다.

[MockMvc Test](/web/back-end/what-is-spring-framework/spring-test/mockmvc-test.md#mockmvc-1)
