Spring Boot Junit5 이해하기 - 환경 구성 및 활용 예제
2025. 6. 10. 09:42ㆍspring/TDD
해당 글에서는 이전에 습득한 이론을 바탕으로 Spring Boot JUnit을 다양한 예제를 통해서 익혀보자.
Spring Boot 2.2 + 이상 버전부터는 기본적으로 의존성이 추가되어 있기에 별도의 세팅은 하지 않는다.
클래스/ 테스트 전후 수행 테스트 : @BeforeAll, @AfterAll, @BeforeEach, @AfterEach
테스트 수행 구조
- @BeforeAll, @AfterAll 어노테이션을 이용하여 테스트 클래스의 시작/후에 단 한번 호출
- @BeforeEach, @AfterEach 어노테이션을 이용하여 매 @Test 전후에 호출
어노테이션 설명
@BeforeAll | JUnit 테스트 클래스 내에서 모든 테스트 메소드 실행 전에 한 번 실행되는 메소드를 정의하는 데 사용됩니다. 보통 테스트 환경의 설정이나 초기화에 사용됩니다. |
@AfterAll | JUnit 테스트 클래스 내에서 모든 테스트 메소드 실행 후에 한 번 실행되는 메소드를 정의하는 데 사용됩니다. 주로 사용한 리소스를 정리하거나 테스트 환경을 종료하는 데 사용됩니다. |
@BeforeEach | JUnit 테스트 클래스 내의 각 테스트 메소드마다 실행되는 메소드를 정의하는 데 사용됩니다. 주로 각 테스트의 준비 작업이나 초기화에 사용됩니다. |
@AfterEach | JUnit 테스트 클래스 내의 각 테스트 메소드 실행 후에 실행되는 메소드를 정의하는 데 사용됩니다. 주로 각 테스트의 후처리 작업이나 정리 작업에 사용됩니다. |
package com.adjh.multiflexapi;
import com.adjh.multiflexapi.model.CodeDto;
import com.adjh.multiflexapi.service.CodeService;
import org.junit.jupiter.api.*;
import org.springframework.beans.factory.annotation.Autowired;
class MultiFlexApiApplicationTests {
@Test
@DisplayName("두 숫자의 합 테스트")
void testEqualsSum() {
System.out.println("[+] @test assertEquals Annotation");
int a = 5;
int b = 7;
int expectedSum = 12;
int actualSum = a + b;
Assertions.assertEquals(expectedSum, actualSum);
}
@Test
@DisplayName("Object NULL 여부 테스트")
void testIsNotNull() {
Object obj = null;
Assertions.assertNull(obj);
System.out.println("[+] @test assertNull Annotation");
}
// 각 테스트 메소드 실행 전에 실행되는 메소드를 정의하는 어노테이션
@BeforeEach
void setUp() {
System.out.println("@BeforeEach Annotation");
}
// 각 테스트 메소드 실행 후에 실행되는 메소드를 정의하는 어노테이션
@AfterEach
void cleanUp() {
System.out.println("@AfterEach Annotation");
}
// 클래스 내의 모든 테스트 메서드 실행 전에 한 번 호출되는 메서드
@BeforeAll
static void setUpBeforeClass() {
System.out.println("@BeforeAll Annotation");
}
// 클래스 내의 모든 테스트 메서드 실행 후에 한 번 호출되는 메서드
@AfterAll
static void cleanUpAfterClass() {
System.out.println("@AfterAll Annotation");
}
}
- 테스트를 시작하면 @BeforeAll 어노테이션을 통해 setUpBeforeClass() 함수가 수행됩니다.
- @Test 어노테이션을 통해 수행되기 이전에 @BeforEach의 setUp() 함수가 수행됩니다.
- @Test 어노테이션을 통해 testEqualsSum() 함수가 수행됩니다.
- @Test 어노테이션을 통해 수행된 후 @AfterEach의 cleanUp() 함수가 수행됩니다.
- 동일한 과정으로 @Test 어노테이션을 통해 수행되기 이전에 @BeforEach의 setUp() 함수가 수행됩니다.
- 동일한 과정으로 @Test 어노테이션을 통해 testIsNotNull() 함수가 수행됩니다.
- 동일한 과정으로 @Test 어노테이션을 통해 수행된 후 @AfterEach의 cleanUp() 함수가 수행됩니다.
- 최종 테스트 종료 이전에 @AfterAll 어노테이션을 통해 cleanUpAfterClass() 함수가 수행됩니다.
Given-When-Then 패턴 시나리오 테스트
섹션 설명
Given : 설정 | 테스트의 초기 상태 또는 사전 조건을 설정합니다. 입력 데이터나 테스트가 실행될 문맥을 지정합니다. |
When : 동작 | 테스트되는 동작 또는 이벤트를 설명합니다. 테스트되는 특정 메서드나 동작을 나타냅니다. |
Then : 검증 | "When" 섹션에서 설명한 동작으로 인해 기대되는 결과 또는 동작을 정의합니다. |
package com.adjh.multiflexapi;
import org.junit.jupiter.api.AfterAll;
import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.BeforeAll;
import org.junit.jupiter.api.Test;
class CalculatorTests {
@BeforeAll
static void setUpBeforeAll() {
System.out.println("@BeforeAll Annotation");
}
@Test
void testAddingTwoNumbers() {
// given : 초기 상태 지정
int a = 2;
int b = 3;
// when : 테스트 동작 정의
int result = Calculator.add(a, b);
// then : 검증
int expected = 5;
Assertions.assertEquals(expected, result);
System.out.println("Test for adding two numbers passed");
}
@Test
void testDividingTwoNumbers() {
// given : 초기 상태 지정
int a = 10;
int b = 2;
// when : 테스트 동작 정의
int result = Calculator.divide(a, b);
// then : 검증
int expected = 5;
Assertions.assertEquals(expected, result);
System.out.println("Test for dividing two numbers passed");
}
@AfterAll
static void cleanUpAfterAll() {
System.out.println("@AfterAll Annotation");
}
}
class Calculator {
static int add(int a, int b) {
return a + b;
}
static int divide(int a, int b) {
return a / b;
}
}
- 테스트를 시작하면 @BeforeAll 어노테이션을 통해 setUpBeforeClass() 함수가 수행됩니다.
- @Test 어노테이션을 통해 testAddingTwoNumbers() 함수가 수행됩니다.
- @Test 어노테이션을 통해 testDividingTwoNumbers() 함수가 수행됩니다.
- 테스트를 종료하면서 @AfterAll 어노테이션을 통해 cleanUpAfterClass() 함수가 수행됩니다.
💡 중첩된 테스트
- 클래스 내에서 테스트가 많이 있어서 가독성이 떨어지는 경우 클래스 내에 클래스를 구현하여서 @Nested 어노테이션을 통해서 테스트 별로 묶어서 수행하는 방법
- 이를 통해 테스트들을 구조화하여 가독성을 향상
💡 @Nested
- JUnit에서 중첩된 테스트 클래스를 작성하는 데 사용
- 중첩된 테스트 클래스는 특정 테스트 그룹을 더 잘 구조화하고 테스트 코드의 가독성을 향상
- 중첩된 테스트 클래스는 내부 클래스로 선언되며, 외부 테스트 클래스의 인스턴스와 상호작용 가능
- 이를 통해 외부 테스트 클래스의 상태를 공유하거나 테스트 케이스 간의 의존성을 관리
package com.adjh.multiflexapi;
import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.Nested;
import org.junit.jupiter.api.Test;
class NestedTests {
@Nested
class CalcTests {
@Test
@DisplayName("두 숫자의 합 테스트")
void testSum() {
int a = 5;
int b = 7;
int expectedSum = 12;
int actualSum = a + b;
Assertions.assertEquals(expectedSum, actualSum);
}
@DisplayName("두 숫자의 합 테스트")
@Test
void testAddingTwoNumbers() {
// given : 초기 상태 지정
int a = 2;
int b = 3;
// when : 테스트 동작 정의
int result = Calculator.add(a, b);
// then : 검증
int expected = 5;
Assertions.assertEquals(expected, result);
System.out.println("Test for adding two numbers passed");
}
@Test
@DisplayName("두 수의 값 나누기 ")
void testDividingTwoNumbers() {
// given : 초기 상태 지정
int a = 10;
int b = 2;
// when : 테스트 동작 정의
int result = Calculator.divide(a, b);
// then : 검증
int expected = 5;
Assertions.assertEquals(expected, result);
System.out.println("Test for dividing two numbers passed");
}
}
@Nested
class IsNotNullTest {
@Test
@DisplayName("Object NULL 여부 테스트")
void testIsNotNull() {
Object obj = null;
Assertions.assertNull(obj);
System.out.println("[+] @test assertNull Annotation");
}
}
}
- @Nested 어노테이션이나 @Test 어노테이션은 순서를 보장하지 않기에 구성한 예시로 확인
- 테스트를 시작하면 @Nested 어노테이션을 통해 CalcTests Class가 수행이 됩니다.
- CalcTests 클래스 내에서 @Test 어노테이션을 확인하여 testSum() 메서드가 수행이 됩니다.
- CalcTests 클래스 내에서 @Test 어노테이션을 확인하여 testAddingTwoNumbers() 메서드가 수행이 됩니다.
- CalcTests 클래스 내에서 @Test 어노테이션을 확인하여 testDividingTwoNumbers() 메서드가 수행이 됩니다.
- 다음으로 @Nested 어노테이션을 통해 IsNotNullTests Class가 수행이 됩니다.
- IsNotNullTests 클래스 내에서 testsNotNull() 메서드가 수행됩니다.
- 테스트가 종료됩니다.
@SpringBootTest 어노테이션을 사용하여 테스트
- @SpringBootTest 를 사용하면 애플리케이션 컨텍스트를 로드하고 필요한 빈을 초기화하는 등 테스트에 필요한 설정과 의존성을 설정하는데 도움이 됨
- 이를 통해 실제 환경과 유사한 설정에서 테스트를 수행하고 각각의 컴포넌트가 상호작용하는 방식을 확인 가능
- 애플리케이션의 다양한 컴포넌트를 테스트할 수 있으며, 외부 서비스와의 상호작용, 데이터베이스 연동 등을 포함한 실제 환경에서의 동작을 확인 가능
- @SpringBootTest 를 선언하면 @Test 를 수행하면서 아래와 같이 로컬 서버가 수행되면서 테스트가 진행되는 것을 확인 가능
package com.adjh.multiflexapi;
import com.adjh.multiflexapi.model.CodeDto;
import com.adjh.multiflexapi.service.CodeService;
import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
@SpringBootTest
class ServiceTests {
@Autowired
private CodeService codeService;
@Test
@DisplayName("코드리스트 테스트 ")
void codeList() {
System.out.println("[+] 코드리스트를 조회합니다.");
// Given
CodeDto codeDto = CodeDto.builder().cd("java").build();
// When
CodeDto resultDto = codeService.selectCode(codeDto);
// Then
Assertions.assertNotNull(resultDto);
}
}
- 클래스 내에 @SpringBootTest 어노테이션을 선언하였습니다. (*이는 @Test 어노테이션 수행직전에 수행이 됩니다)
- 테스트를 시작하면 @BeforeAll 어노테이션을 통해 setUpBeforeClass() 함수가 수행됩니다.
- @Test 어노테이션이 수행되기 직전에 로컬 서버가 실행이 되어 각각의 컨텍스트를 로드해 옵니다.
- @Test 어노테이션을 통해 testIsNotNullCodeList() 함수가 수행됩니다.
- 테스트를 종료하면서 @AfterAll 어노테이션을 통해 cleanUpAfterClass() 함수가 수행됩니다.
'spring > TDD' 카테고리의 다른 글
Spring Boot3 403, 401 - MockMvc, Spring Security Test (0) | 2025.06.12 |
---|---|
Spring Boot MockMvc 이해하기 : 테스트 흐름 및 사용예제 (1) | 2025.06.12 |
Spring Boot JUnit5 이해하기 - 이론 및 구조 (0) | 2025.06.10 |
MockMvc, @Transactional(readOnly = true)와 @Transactional을 분리하라고? (0) | 2024.01.23 |
deleteAll()보다 deleteAllInBatch()가 더 권장되는 이유가 뭐야? (0) | 2024.01.15 |