JUnit5로 테스트 코드 작성하기

hoonssac·2024년 3월 17일

Spring

목록 보기
9/18
post-thumbnail

안녕하세요 ╰(°▽°)╯
오늘은 앞으로 진행할 프로젝트에서 중요한 과정 중 하나인 테스트 코드를 작성해보겠습니다.

제가 한 달 전쯤, 정보처리기사 필기 공부를 하면서 애플리케이션 테스트의 종류와 개념에 대해 정리한 글이 있는데, 자세한 내용이 궁금하시다면 해당 포스트를 참고해주세요 👍


테스트 코드 작성 이유

먼저, 테스트 코드를 왜 작성해야 할까요?

✔️빠른 피드백

제가 가장 큰 이유라고 생각하고, 가장 크게 체감하는 것은 바로 빠른 피드백입니다.
단위 테스트에 대해 배우기 전에 저는 이런 방식으로 개발을 진행했습니다.

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

여기서 2번~5번은 코드를 수정할 때마다 반복해야 하기 때문에, 굉장히 번거로웠습니다. 😂

하지만 테스트 코드를 작성하면 이런 문제가 해결되므로 굳이 직접 프로그램을 재시작 할 필요가 없어지게 되는 것이죠..!😉


테스트 코드 작성 도구

테스트 코드 작성을 도와주는 여러 프레임워크들이 있습니다.
가장 대중적인 테스트 프레임워크로는 xUnit이 있는데 이는 개발환경에 따라 Unit 테스트를 도와주는 도구라고 생각하면 됩니다.

대표적인 xUnit 프레임워크들은 다음과 같습니다.

  • JUnit - Java
  • DBUnit - DB
  • CppUnit - C++
  • NUnit - .net

이 중에서 저는 자바용인 JUnit을 사용할 것입니다.🙌


Hello Controller 테스트 코드 작성하기

메인 클래스 생성

지난 포스트에서 프로젝트 환경을 구축했었는데, 메인 클래스를 아직 안만들었죠?
우선 메인 클래스부터 이렇게 만들어 주겠습니다.

package com.b1uesoda.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, args);
    }
}

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

그리고 main 메소드에서 실행하는 저 SpringApplication.run으로 인해 내장 WAS(Web Application Server)가 실행되는 과정을 거칩니다. 여기서 내장 WAS란 별도로 외부에 WAS를 두지 않고 애플리케이션을 실행할 때 내부에서 WAS를 실행하는 것을 말합니다.

HelloController 생성

그럼 이제 테스트를 위한 Controller를 만들어 볼까요?
저는 web이라는 패키지를 만들어 HelloController라는 이름의 클래스를 만들고 간단한 API를 만들었습니다.

package com.b1uesoda.springboot.web;

import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;

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

여기서 @RestController는 컨트롤러를 JSON을 반환하는 컨트롤러로 만들어주는 역할을 하는 어노테이션입니다.

작성한 코드가 제대로 작동하는지 테스트 코드로 검증을 해보겠습니다.

Dependency 추가

❗테스트 코드를 작성하기 전에, 저는 JUnit5 버전을 사용할 것이기 때문에,built.gradle에 dependency를 다음과 같이 설정했습니다!

dependencies {
    testImplementation('org.junit.jupiter:junit-jupiter-api:5.7.0')
    testRuntimeOnly('org.junit.jupiter:junit-jupiter-engine:5.7.0')
    testImplementation('org.junit.jupiter:junit-jupiter-params:5.7.0')
    
    implementation('org.springframework.boot:spring-boot-starter-web')
    testImplementation('org.springframework.boot:spring-boot-starter-test')
}

테스트 코드 작성


이렇게 test/java에 패키지를 똑같이 만들어 HelloControllerTest 클래스를 생성해주었습니다.

package com.b1uesoda.springboot.web;

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.content;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;

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

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

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

스프링 부트를 배워가는 단계이기 때문에 간단하게 코드를 설명하겠습니다.

@RunWith(SpringRunner.class)
  • 테스트를 진행할 때 JUnit에 내장된 실행자 외에 다른 실행자를 실행시킵니다.
  • 여기서는 SpringRunner라는 스프링 실행자를 사용합니다.
  • 즉, 스프링 부트 테스트와 JUnit 사이에 연결자 역할을 합니다.
@WebMvcTest(controllers = HelloController.class)
  • 여러 스프링 테스트 어노테이션 중, Web에 집중할 수 있는 어노테이션입니다.
  • 선언할 경우 @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를 검증합니다.
  • 우리가 흔히 알고 있는 200, 404, 500 등의 상태를 검증합니다.
  • 여기선 OK 즉, 200인지 아닌지를 검증합니다.
.andExpect(content().string(hello));
  • mvc.perform의 결과를 검증합니다.
  • 응답 본문의 내용을 검증합니다.
  • Controller에서 "hello"를 리턴하기 때문에 이 값이 맞는지 검증합니다.

테스트 실행

이렇게 코드를 모두 작성했으니, 한 번 실행해보겠습니다 👻


다음과 같이 테스트가 통과하는 것을 확인할 수 있습니다!

그럼 메인 메소드를 실행시켜 localhost:8080/hello로 접속해보겠습니다.

그랬더니 다음과 같이 문자열 hello가 잘 출력된 것을 확인할 수 있습니다.


오늘은 이렇게 견고한 소프트웨어를 만드는 중요한 요소 중 하나인 테스트 코드를 간단하게 만들어 보았습니다!

이러한 과정이 아직 익숙하지는 않지만, 나중에 발생할 번거로움에 대비해 꼭 필요한 단계라는 생각이 드네요😏

그럼 다음 포스트로 찾아뵙겠습니다. 읽어주셔서 감사합니다 :)


📚Reference
스프링 부트와 AWS로 혼자 구현하는 웹 서비스 - 이동욱
JUnit5 테스트 코드 작성하기

profile
훈싹의 개발여행

0개의 댓글