
이 글은 스프링부트3 백엔드 개발자 되기 책을 바탕으로 공부한 내용을 정리한 게시글 입니다.
테스트코드는 작성한 코드가 의도대로 잘 동작하고 예상치 못한 문제가 없는지 확인 할 목적으로 작성하는 코드 입니다. 테스트 코드를 잘 익히게 되면 유지보수에도 좋고 코드 수정 시 기존 기능이 제대로 작동하지 않을까봐 걱정하지 않아도 된다는 장점이 있습니다.
1. 테스트 코드란?(given-when-then 패턴)
테스트 코드는 test디렉터리에서 작업합니다. 우리의 프로젝트에도 이미 test 디렉터리가 있습니다.

테스트 코드에는 다양한 패턴이 있습니다. 그중에서도 given-when-then패턴을 사용해보겠습니다.
given-when-then 패턴은 테스트 코드를 세 단계로 구분해 작성하는 방식을 말합니다. 1. given은 테스트 실행을 준비하는 단계 2. when은 테스트를 진행하는 단계 3.then은 테스트 결과를 검증하는 단계입니다.
예를 들어 새로운 메뉴를 저장하는 코드를 테스트한다고 가정해보고 given, when, then을 적용해 구현해 보겠습니다.
@DisplayName("새로운 메뉴를 저장한다.")
@Test
public void saveMenuTest() {
// 1. given: 메뉴를 저장하기 위한 준비 과정
final String name = "아메리카노";
final int price=2000;
final Menu americano = new Menu(name, price);
// 2. when : 실제로 메뉴를 저장
final long savedId = menuService.save(americano);
// 3. then : 메뉴가 잘 추가되었는지 검증
final Menu savedMenu = menuService.findById(savedId).get();
assertThat(savedMenu.getName()).isEqualTo(name);
assertThat(savedMenu.getPrice()).isEqualTo(price);
}
코드를 보면 세 부분으로 나누어져 있습니다. 메뉴를 저장하기 위해 준비하는 과정인 given절 실제로 메뉴를 저장하는 when절, 메뉴가 잘 추가 되었는지 검증하는 then절로 나누어져 있습니다.
2. 스프링부트 3 에서의 테스트
스프링부트는 애플리케이션을 테스트하기 위한 도구와 에너테이션을 제공합니다. spring-boot-starter-test 스타터에 테스트를 위한 도구가 모여 있습니다.
- JUnit : 자바 프로그래밍 언어용 단위 테스트 프레임워크
- Spring Test & Spring Boot Test : 스프링 부트 애플리케이션을 위한 통합 테스트 지원
- AssertJ : 검증문인 어설션을 작성하는 데 사용되는 라이브러리
- Hamcrest : 표현식을 이해하기 쉽게 만드는 데 사용되는 Matcher 라이브러리
- Mockito : 테스트에 사용할 가짜 객체인 목 객체를 쉽게 만들고, 관리하고, 검증할 수 있게 지원하는 테스트 프레임워크
- JSONassert : JSON용 어설션 라이브러리
- JsonPath : JSON 데이터에서 특정 데이터를 선택하고 검색하기 위한 라이브러리
이중에서 JUnit과 AssertJ를 가장 많이 사용합니다.
JUnit과 AssertJ를 이용해 테스트코드를 만들어 보겠습니다.
3. JUnit이란?
JUnit은 자바 언어에서의 단위테스트 프레임워크입니다. 단위테스트란 작성한 코드를 작은 단위로 검증하는 것을 의미합니다. 보통 단위는 메서드를 의미합니다. JUnit은 아래와 같은 특징이 있습니다.
- 테스트 방식을 구분 할 수 있는 에너테이션을 제공
- @Test애너테이션으로 메서드를 호출 할 떄마다 새 인스턴트를 생성, 독립테스트 가능
- 예상 결과를 검증하는 어설션 메서드 제공
- 사용 방법이 단순, 테스트 코드 작성 시간이 적음
- 자동 실행, 자체 결과를 확인하고 즉각적인 피드백 제공
이제 Junit으로 단위테스트 코드를 만들어 보겠습니다.
먼저 src → test → java 폴더에 JUnitTest.java 파일을 생성합니다.
이제 테스트 코드를 작성해보겠습니다.
public class JUnitTest {
@DisplayName("1 + 2는 3이다")
@Test
public void junitTest() {
int a = 1;
int b = 2;
int sum = 3;
Assertions.assertEquals(a + b, sum);
}
}
JUnit의 @DisplayName 애너테이션은 테스트 이름을 명시하며, @Test 애너테이션이 붙은 메서드는 테스트를 수행합니다. JUnit은 테스트 간 독립성을 보장하기 위해 각 테스트 실행 시 새로운 객체를 생성하고 종료 후 삭제합니다.
테스트 코드에서는 assertEquals(기대값, 실제값)을 사용하여 a + b와 sum이 같은지 검증하며, 이를 통해 assertEquals의 기본적인 사용법을 익힐 수 있습니다.
실제로 테스트 코드가 동작하는지 확인해 보겠습니다.

콘솔창을 통해 테스트의 결과를 확인 해 볼 수가 있습니다. 사진처럼 성공 여부, 테스트 케이스의 이름, 테그트 실행시간 등을 확인 해 볼 수 있습니다.
만약 결과가 안보이신다면 콘솔창에 체크아이콘을 누르시면 결과가 보입니다.
그럼 만약 테스트가 실패하면 어떻게 결과가 출력되는지 한번 확인해보겠습니다.
JUnitTest() 메서드에 실패코드를 한번 추가해 보겠습니다.
import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.Test;
public class JUnitTest {
@DisplayName("1 + 2는 3이다")
@Test
public void junitTest() {
int a = 1;
int b = 2;
int sum = 3;
Assertions.assertEquals(a + b, sum);
}
@DisplayName("1 + 3는 4이다")
@Test
public void junitFailedTest() {
int a = 1;
int b = 3;
int sum = 3;
Assertions.assertEquals(a + b, sum);
}
}
위 처럼 코드를 작성해 준 뒤 테스트를 실행해보겠습니다.

사진처럼 테스트가 실패한 것을 확인 할 수 있습니다.
이제 JunitFailedTest()메서드를 삭제한 후 JUnitCycleTest.java 파일을 만들어 JUnit에 각 애너테이션들을 알아보겠습니다.
import org.junit.jupiter.api.*;
public class JUnitCycleTest {
@BeforeAll //전체 테스트를 시작하기 전에 1회 실행하므로 메서드는 static으로 선언
static void beforeAll() {
System.out.println("@BeforeAll");
}
@BeforeEach // 테스트 케이스스를 시작하기 전마다 실행
public void beforeEach() {
System.out.println("@BeforeEach");
}
@Test
public void test1() {
System.out.println("test1");
}
@Test
public void test2() {
System.out.println("test2");
}
@Test
public void test3() {
System.out.println("test3");
}
@AfterAll // 전ㅊ체 테시트를 마치고 종료하기 전에 1회 실행하므로 메서드는 static으로 선언
static void afterAll() {
System.out.println("@AfterAll");
}
@AfterEach // 테스트 케이스를 종료하기 전마다 실행
public void afterEach() {
System.out.println("@AfterEach");
}
}
테스트 코드는 에너테이션에 따라 실행순서가 정해집니다. 각 애너테이션에 대해 자세히 알아보겠습니다.
- @BeforeAll : 전체 테스트를 시작하기 전에 처음으로 한번만 실행합니다. 예를 들어 데이터 베이스를 연결해야 하거나 테스트 환경을 초기화 할 때 사용됩니다. 이 애너테이션은 전체 테스트 실행 주기에서 한번만 호출되어야 하기 때문에 메서드를 staitc으로 선언해야 합니다.
- @BeforeEach : 테스트 케이스를 시작하기 전에 매번 실행합니다. 예를 들어 테스트 메서드에 사용하는 객체를 초기화 하기나 테스트에 필요한 값을 미리 넣을 때 사용 할 수 있습니다. 각 인스턴스에 대해 메서드를 호출해야 하므로 메서드는 static이 아니어야 합니다.
- @AfterAll : 전체 테스트를 마치고 종료하기 전에 한번만 실행합니다. 예를 들어 데이터베이스 연결을 종료 할 때나 공통적으로 사용하는 자원을 헤제 할 때 사용 할 수 있습니다. 전체 테스트 실행 주기에서 한번만 호출되어야 하므로 메서드를 staitc으로 선언해야 합니다.
- @AfterEach : 각 테스트 케이스를 종료하기 전에 매번 실행합니다. 예를 들어 테스트 이후에 특정 데이터를 삭제해야 하는 경우 사용합니다. @BeforeEach와 마찬가지로 메서드는 static이 아니어야 합니다.
에너테이션을 중심으로 JUnit테스트코드를 살펴보면 다음과 같습니다. @BeforeEach부터 @AfterEach까지 테스트 개수만큼 반복된 결과물을 볼 수 있습니다.

테스트 코드를 실행시켜서 결과를 확인해 보겠습니다.

결과를 확인해보면 @BeforeAll 에너테이션으로 설정한 메서드가 실행되고 그 이후에는 테스트 케이스 개수만큼 @BeforeEach → @Test → @AfterEach 의 생명주기로 테스트가 진행됩니다. 모든 테스트 케이스가 끝나면 @AfterAll 애너테이션으로 설정한 메서드를 실행하고 종료하는 걸 확인 할 수 있습니다.
4. AssertJ
JUnit과 함께 사용하면 정말 좋은 AssertJ입니다.
AssertJ는 JUnit과 함꼐 사용해 검증문의 가독성을 확 높여주는 라이브러리 입니다. 예를 들어 밑에 테스트 코드 같은 경우 기대값과 실제 비교값을 명시하지 않으므로 비교 대상이 햇갈립니다.
Assertions.assertEquals(sum, a+b);
보기에는 큰 문제가 없어 보이지만 대규모 프로젝트에서는 좀 더 명확한 코드를 통해 실수를 줄여야 하기 떄문에 가독성은 정말 중요한 문제입니다.
이제 AssertJ를 사용하여 가독성을 개선해보겠습니다.
assertThat(a+b).isEqualTo(sum);
이렇게 작성하면 a+b는 sum과 같아야한다로 명확하게 읽히기 때문에 코드를 읽는 사람이 햇갈리지 않습니다. AssertJ는 다양한 메서드를 제공합니다. 자주 사용하는 메서드를 정리해보겠습니다.
| 메서드 이름 | 설명 |
| isEqualTo(A) | A 값과 같은지 검증 |
| isNotEqualTo(A) | A 값과 다른지 검증 |
| contains(A) | A 값을 포함하는지 검증 |
| doesNotContain(A) | A 값을 포함하지 않는지 검증 |
| startsWith(A) | 접두사가 A인지 검증 |
| endsWith(A) | 접미사가 A인지 검증 |
| isEmpty( ) | 비어 있는 값인지 검증 |
| isNotEmpty( ) | 비어 있지 않은 값인지 검증 |
| isPositive( ) | 양수인지 검증 |
| isNegative( ) | 음수인지 검증 |
| isGreaterThan(1) | 1보다 큰 값인지 검증 |
| isLessThan(1) | 1보다 작은 값인지 검증 |
5. AssertJ 작성 예시
String으로 선언한 변수 3개가 있습니다. 여기에서 세 변수 모두 Null이 아니며 name1과 name2는 같은 값을 가지고 name3는 다른 나머지 두 변수와 다른 값을 가지는데 이를 검증하는 테스트 코드를 어떻게 짜야할까요
@Test
public void junitTest(){
String mane1 = "홍길동";
String name2 = "홍길동";
String name3 = "홍길은";
// 1. 모든 변수가 null이 아닌지 확인
// 2. name1과 name2가 같은 지 확인
// 3. name1과 name3가 다른지 확인
자 문제 입니다. 다음 예제를 위 조건과 맞게 테스트 할려면 코드를 어떻게 짜야 할까요?
정답은 다음과 같습니다.
@Test
public void junitTest(){
String mane1 = "홍길동";
String name2 = "홍길동";
String name3 = "홍길은";
// 1. 모든 변수가 null이 아닌지 확인
// 2. name1과 name2가 같은 지 확인
// 3. name1과 name3가 다른지 확인
// 1. 모든 변수가 null이 아닌지 확인
assertThat(name1).isNotNull();
assertThat(name2.isNotNull();
assertThat(name3.isNotNull();
// 2. name1과 name2가 같은 지 확인
assertThat(name1).isEqualsTo(name2);
// 3. name1과 name3가 다른지 확인
assertThat(name1).isNoutEqualTo(name3);
}
두번째 예제입니다. 이번에는 int로 선언된 변수 3개가 있습니다. number1, number2, number3은 각각 15, 0, -1 의 값을 가집니다. 세 변수가 각각 양수, 0 ,음수이고 number1은 number2보다 큰 값이고 number3는 number2보다 작은 값임을 검증하는 테스트를 작성해보세요.
@Test
public void junitTest2(){
int number1 = 15;
int number2 = 0;
int number3 = -5;
// 1.number1은 양수인지 확인
// 2.numver2는 0인지 확인
// 3.number3은 음수인지 확인
// 4.number1은 number2보다 큰지 확인
// 5.number3은 number2보다 작은지 확인
정답은 다음과 같습니다.
@Test
public void junitTest2(){
int number1 = 15;
int number2 = 0;
int number3 = -5;
// 1.number1은 양수인지 확인
// 2.numver2는 0인지 확인
// 3.number3은 음수인지 확인
// 4.number1은 number2보다 큰지 확인
// 5.number3은 number2보다 작은지 확인
// 1.number1은 양수인지 확인
assertThat(number1).isPositive();
// 2.number2는 0인지 확인
assertThat(number2).isZero();
// 3.number3은 음수인지 확인
assertThat(number3).isNegative();
// 4.number1은 number2보다 큰지 확인
assertThat(number1).isGreaterThan(number2);
// 5.number3은 number2보다 작은지 확인
assertThat(number3).isLessThan(number2);
}
이렇게 AssertJ를 이용하면 코드가 굉장히 직관적인 걸 확인 할 수 있습니다.
'개발자 취업준비 > springboot' 카테고리의 다른 글
| ORM이란? JPA와 myBatis 차이 (1) | 2025.02.04 |
|---|---|
| 프로젝트 바탕으로 테스트 코드 작성해보기 (0) | 2025.02.01 |
| 스프링부트 계층구조 구현하여 프로젝트를 구성해보기 (1) | 2025.01.29 |
| 스프링부트 계층구조 (1) | 2025.01.28 |
| PSA(이식 가능한 서비스 추상화) (7) | 2025.01.21 |