단위테스트와 TDD는 다른 것!
TDD는 테스트가 주도하는 개발로써 레드 그린 싸이클을 따른다.
항상 실패하는 테스트를 먼저 작성하고(Red)
테스트가 통과하는 프로덕션 코드를 작성하고(Green)
테스트가 통과하면 프로덕션 코드를 리팩토링하기(Refactor)

단위 테스트는 TDD의 첫 번째 단계인 '기능 단위의 테스트 코드를 작성하는 것'으로 아래와 같은 이점을 가지고 있다.
1) 개발 단계 초기에 문제를 발견하게 도와줌
2) 개발자가 나중에 코드를 리팩토링하거나 라이브러리 업그레이드 등을 하면 기존 기능이 올바르게 작동하는지 확인할 수 있음(ex. 회귀테스트)
3) 기능에 대한 불확실성을 감소시킬 수 있음
4) 시스템에 대한 실제 문서를 제공, 단위테스트 자체가 문서로 사용할 수 있음
단위테스트와 TDD의 차이점을 알았으니 이제 SpringBoot에서는 어떻게 단위테스트를 하는지 살펴보자!
테스트를 하기 위해서는 스프링 부트에서 제공하는 테스터를 사용해야한다.
나는 build.gradle에 초기 세팅을 아래와 같이 하였다.
buildscript {
ext {
springBootVersion = '2.1.9.RELEASE'
}
repositories {
mavenCentral()
jcenter()
}
dependencies {
classpath("org.springframework.boot:spring-boot-gradle-plugin:${springBootVersion}")
}
}
apply plugin: 'java'
apply plugin: 'eclipse'
apply plugin: 'org.springframework.boot'
apply plugin: 'io.spring.dependency-management'
group 'com.yaliny.book'
version '1.0-SNAPSHOT'
sourceCompatibility = 1.8
repositories {
mavenCentral()
jcenter()
}
/* 7버전에서는 compile, testComplie 대신 implementataion, testImplementation을 사용해야 에러가 안남.
<에러 로그>
A problem occurred evaluating root project 'com.yaliny.book'.
> Could not find method compile() for arguments [org.springframework.boot:spring-boot-starter-web] on object of type org.gradle.api.internal.artifacts.dsl.dependencies.DefaultDependencyHandler.
*/
dependencies {
implementation('org.springframework.boot:spring-boot-starter-web')
testImplementation('org.springframework.boot:spring-boot-starter-test')
}
아래 설정이 스프링 부트에서 기본적으로 제공하는 테스트 스타터이다.
JUnit 뿐만 아니라 웬만한 Java 계열의 언어에서 사용하는 테스트 라이브러리들이 모여있다.
(해당 테스트 라이브러리에 대한 자세한 내용은 링크를 참조하면 좋을 거 같다. https://blog.neonkid.xyz/218)
testImplementation('org.springframework.boot:spring-boot-starter-test')
gradle 빌드가 완료되었으면 프로젝트명.springboot 패키지를 만든 후에 스프링 부트의 자동 설정을 위해 Application 클래스를 생성하였다.
package com.yaliny.book.springboot;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
/*
[@SpringBootApplication 설명]
스프링 부트의 자동 설정, 스프링 Bean 읽기와 생성 모두 자동으로 설정됨.
해당 어노테이션이 있는 위치부터 설정을 읽어가기 때문에 해당 어노테이션이 있는 클래스는 항상 프로젝트의 최상단에 위치 해야함
*/
@SpringBootApplication // 스프링 부트의 자동 설정, 스프링 Bean 읽기와 생성 모두 자동으로 설정됨.
public class Application {
public static void main(String[] args) {
/*
SpringApplication.run으로 인하여 내장 WAS를 실행
내장 WAS란? 별도로 외부에 WAS를 두지않고 애플리케이션을 실행할 때 내부에서 WAS를 실행하는 것
서버에 톰캣을 설치할 필요가 없게되고 스프링 부트로 만들어진 Jar 파일로 실행하면 된다.
*/
SpringApplication.run(Application.class, args);
}
}
그 후에 web 패키지를 만들고 HelloController를 생성
package com.yaliny.book.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";
}
}
작성한 코드가 제대로 작동하는지 테스트를 하기 위해 src/test/java에도 main과 동일하게 패키지를 생성한 뒤 HelloControllerTest 클래스를 생성하였다.
package com.yaliny.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.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;
@RunWith(SpringRunner.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));
}
}
해당 테스트 코드에 대한 설명을 하자면 다음과 같다.
1. @RunWith(SpringRunner.class)
테스트를 진행할 때 JUnit에 내장된 실행자 외에 다른 실행자를 실행시킨다.
여기서는 SpringRunner라는 스프링 실행자를 사용
즉, 스프링 부트 테스트와 JUnit 사이에 연결자 역할은 한다.
2. @WebMvcTest
여러 스프링 테스트 어노테이션 중 Web(Spring MVC)에 집중할 수 있는 어노테이션
선언할 경우 @Controller, @ControllerAdvice 등을 사용할 수 있음
단, @Service, @Component, @Repository 등은 사용할 수 없음
여기서는 컨트롤러만 사용하기 때문에 선언
3. @Autowired
스프링이 관리하는 빈(Bean)을 주입받음
4. private MockMvc 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"를 리턴하기 때문에 이 값이 맞는지 검증
해당 테스트 코드를 실행시키면 아래와 같이 검증 성공이 된다.

오늘은 간단한 단위테스트 예제를 만들어보았다. 단위테스트와 관련된 내용은 추후에도 정리할 예정이다!
'TIL > Spring' 카테고리의 다른 글
[Spring] 빈 생명주기 콜백 이란? - 스프링 초기화, 소멸 메서드 사용하기 (0) | 2025.03.04 |
---|---|
[Spring] 찍어먹어보자! Spring Security와 인증/인가란 무엇인가?(feat. 로그인, 로그아웃, 회원가입 간단 구현) (0) | 2025.02.02 |
[TIL/Spring] 스프링 시큐리티와 OAuth 2.0으로 구글 로그인 기능 구현 (0) | 2022.10.30 |
[TIL] 비즈니스 로직을 처리하는 곳은 Service가 아니다? (0) | 2022.10.09 |
[TIL] Spring Framework - HandlerInterceptorAdapter (0) | 2022.09.28 |