반응형
해당 글에서는 이전에 습득한 이론을 바탕으로 Spring Boot JUnit을 다양한 예제를 통해서 익힙니다.
💡 [참고] 이전에 작성한 Test 관련 글들을 읽으시면 도움이 됩니다.
분류 | 링크 |
JUnit 5 이론 및 구성 요소 | https://adjh54.tistory.com/341 |
JUnit 5 환경구성 및 활용예제 | https://adjh54.tistory.com/342 |
JUnit 5 + Mockito 이론 및 활용예제 | https://adjh54.tistory.com/346 |
JUnit 5 + MockMvc 이론 및 활용예제 | https://adjh54.tistory.com/347 |
Assertions API Document | https://adjh54.tistory.com/348 |
개발방법론 TDD, BDD | https://adjh54.tistory.com/305 |
JUnit 5 + Mockito + MockMVC 사용예제 Github | https://github.com/adjh54ir/blog-codes/tree/main/spring-boot-test |
1) JUnit 5 초기 환경 구성
💡 Spring Boot 2.2.+ 이상 버전부터는 기본적으로 의존성이 추가되어 있기에 별도의 세팅은 하지 않습니다. 혹시나 아래의 코드가 추가되지 않았다면 추가하시면 됩니다.
dependencies {
testImplementation 'org.springframework.boot:spring-boot-starter-test'
}
test {
useJUnitPlatform()
}
Maven Repository: org.springframework.boot » spring-boot-starter-test
2) JUnit 5 사용 예시 -1 : 라이프사이클 테스트
💡 JUnit 5 사용 예시
- JUnit의 사용예시를 통해서 각각 어노테이션과 메서드의 사용법을 알아봅니다.
1. @Test를 이용한 일반적인 테스트 : @Test
💡 @Test를 이용한 일반적인 테스트 : @Test
- @Test 어노테이션을 이용하여 기본적인 테스트를 확인해봅니다.
💡 @Test
- JUnit에서 메서드를 테스트 메소드로 표시하는 데 사용됩니다.
- 테스트 클래스가 실행되면 JUnit은 @Test로 주석이 달린 메소드를 개별적인 테스트 케이스로 식별하여 실행합니다.
1.1. 테스트 수행구조
💡 테스트 수행구조
- 테스트를 시작하면 @Test 어노테이션을 통해 testSum()이라는 함수를 수행시키고 종료합니다.
1.2. 코드 사용예시
💡 코드 사용예시
- 해당 테스트에서는 두 숫자의 합이 맞는지 여부를 확인하는 테스트를 구성하였습니다.
- a + b의 값과 expectedSum값을 비교했을 때 해당 결과값이 맞는지에 대해 확인합니다.
package com.adjh.multiflexapi;
import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.Test;
/**
* 메인 테스트
*
* @author : lee
* @fileName : MultiFlexApiApplicationTests
* @since : 12/6/23
*/
class MultiFlexApiApplicationTests {
@Test
@DisplayName("두 숫자의 합 테스트")
void testSum() {
int a = 5;
int b = 7;
int expectedSum = 12;
int actualSum = a + b;
Assertions.assertEquals(expectedSum, actualSum);
}
}
1.3. 결과 확인
💡 해당 값이 맞는 경우 : ‘테스트 통과’ 메시지를 출력합니다.
💡 해당 값이 틀린 경우 : ‘테스트 실패’ 메시지를 출력합니다.
2. 클래스/테스트 전후 수행 테스트 : @BeforeAll, @AfterAll, @BeforeEach, @AfterEach
💡 클래스/테스트 전후 수행 테스트
- @BeforeAll, @AfterAll 어노테이션을 이용하여 테스트 클래스의 시작/후에 단 한번 호출이 됩니다.
- @BeforeEach, @AfterEach 어노테이션을 이용하여 매 @Test 전후에 호출이 됩니다.
어노테이션 | 설명 |
@BeforeAll | JUnit 테스트 클래스 내에서 모든 테스트 메소드 실행 전에 한 번 실행되는 메소드를 정의하는 데 사용됩니다. 보통 테스트 환경의 설정이나 초기화에 사용됩니다. |
@AfterAll | JUnit 테스트 클래스 내에서 모든 테스트 메소드 실행 후에 한 번 실행되는 메소드를 정의하는 데 사용됩니다. 주로 사용한 리소스를 정리하거나 테스트 환경을 종료하는 데 사용됩니다. |
@BeforeEach | JUnit 테스트 클래스 내의 각 테스트 메소드마다 실행되는 메소드를 정의하는 데 사용됩니다. 주로 각 테스트의 준비 작업이나 초기화에 사용됩니다. |
@AfterEach | JUnit 테스트 클래스 내의 각 테스트 메소드 실행 후에 실행되는 메소드를 정의하는 데 사용됩니다. 주로 각 테스트의 후처리 작업이나 정리 작업에 사용됩니다. |
2.1. 테스트 수행 구조
💡 테스트 수행구조
1. 테스트를 시작하면 @BeforeAll 어노테이션을 통해 setUpBeforeClass() 함수가 수행됩니다.
2. @Test 어노테이션을 통해 수행되기 이전에 @BeforEach의 setUp() 함수가 수행됩니다.
3. @Test 어노테이션을 통해 testEqualsSum() 함수가 수행됩니다.
4. @Test 어노테이션을 통해 수행된 후 @AfterEach의 cleanUp() 함수가 수행됩니다.
5. 동일한 과정으로 @Test 어노테이션을 통해 수행되기 이전에 @BeforEach의 setUp() 함수가 수행됩니다.
6. 동일한 과정으로 @Test 어노테이션을 통해 testIsNotNull() 함수가 수행됩니다.
7. 동일한 과정으로 @Test 어노테이션을 통해 수행된 후 @AfterEach의 cleanUp() 함수가 수행됩니다.
8. 최종 테스트 종료 이전에 @AfterAll 어노테이션을 통해 cleanUpAfterClass() 함수가 수행됩니다.
2.2. 코드 사용예시
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;
/**
* 메인 테스트
*
* @author : lee
* @fileName : MultiFlexApiApplicationTests
* @since : 12/6/23
*/
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");
}
}
2.3. 수행 결과
💡 수행 결과
- @Test로 구성한 두 개의 메서드가 성공적으로 수행되었습니다.
- @BeforeAll, @AfterAll의 경우는 테스트의 시작 전후에 한 번씩만 수행되었고@BeforeEach, @AfterEach의 경우는 @Test로 구성한 메서드의 전후에 각각 수행이 되었습니다.
3. Given-When-Then 패턴 시나리오 테스트
💡 Given-when-then 패턴 시나리오 테스트하기
- @Test를 선언한 메서드에서 시나리오를 구성하기 위해 Given-When-Then 패턴을 통하여서 시나리오를 구성합니다.
섹션 | 설명 |
Given : 설정 | 테스트의 초기 상태 또는 사전 조건을 설정합니다. 입력 데이터나 테스트가 실행될 문맥을 지정합니다. |
When : 동작 | 테스트되는 동작 또는 이벤트를 설명합니다. 테스트되는 특정 메서드나 동작을 나타냅니다. |
Then : 검증 | "When" 섹션에서 설명한 동작으로 인해 기대되는 결과 또는 동작을 정의합니다. |
3.1. 테스트 수행구조
💡 테스트 수행구조
1. 테스트를 시작하면 @BeforeAll 어노테이션을 통해 setUpBeforeClass() 함수가 수행됩니다.
2. @Test 어노테이션을 통해 testAddingTwoNumbers() 함수가 수행됩니다.
3. @Test 어노테이션을 통해 testDividingTwoNumbers() 함수가 수행됩니다.
4. 테스트를 종료하면서 @AfterAll 어노테이션을 통해 cleanUpAfterClass() 함수가 수행됩니다.
3.2. 코드 사용예시
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;
/**
* 중첩 테스트 클래스
*
* @author : lee
* @fileName : CalculatorTests
* @since : 12/7/23
*/
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;
}
}
3.3. 수행 결과
💡 수행 결과
- 시작 전후에 @BeforAll, @AfterAll로 지정한 메서드가 실행이 되었습니다.
- @Test로 지정한 testAddingTwoNumbers(), testDividingTwoNumbers() 함수가 실행이 되었습니다.
4. 중첩된 테스트 : @Nested
💡 중첩된 테스트
- 클래스 내에서 테스트가 많이 있어서 가독성이 떨어지는 경우 클래스 내에 클래스를 구현하여서 @Nested 어노테이션을 통해서 테스트 별로 묶어서 수행하는 방법입니다.
- 이를 통해 테스트들을 구조화하여 가독성을 향상하는데 도움을 줍니다.
💡 @Nested
- JUnit에서 중첩된 테스트 클래스를 작성하는 데 사용됩니다. 중첩된 테스트 클래스는 특정 테스트 그룹을 더 잘 구조화하고 테스트 코드의 가독성을 향상시키는 데 도움이 됩니다.
- 중첩된 테스트 클래스는 내부 클래스로 선언되며, 외부 테스트 클래스의 인스턴스와 상호작용할 수 있습니다. 이를 통해 외부 테스트 클래스의 상태를 공유하거나 테스트 케이스 간의 의존성을 관리할 수 있습니다
4.1. 테스트 수행구조
💡 테스트 수행구조
- @Nested 어노테이션이나 @Test 어노테이션은 순서를 보장하지 않기에 구성한 예시로 확인해 주시면 좋을 것 같습니다.
1. 테스트를 시작하면 @Nested 어노테이션을 통해 CalcTests Class가 수행이 됩니다.
2. CalcTests 클래스 내에서 @Test 어노테이션을 확인하여 testSum() 메서드가 수행이 됩니다.
3. CalcTests 클래스 내에서 @Test 어노테이션을 확인하여 testAddingTwoNumbers() 메서드가 수행이 됩니다.
4. CalcTests 클래스 내에서 @Test 어노테이션을 확인하여 testDividingTwoNumbers() 메서드가 수행이 됩니다.
5. 다음으로 @Nested 어노테이션을 통해 IsNotNullTests Class가 수행이 됩니다.
6. IsNotNullTests 클래스 내에서 testsNotNull() 메서드가 수행됩니다.
7. 테스트가 종료됩니다.
4.2. 코드 사용 예시
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;
/**
* 중첩화 된 테스트
*
* @author : lee
* @fileName : NestedTests
* @since : 12/8/23
*/
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");
}
}
}
4.3. 수행 결과
💡 수행 결과
- NestedTests 클래스 안에 CalcTests와 IsNotNullTest 클래스가 존재하는데, 각각 모두 수행이 됨을 확인하였습니다.
3) JUnit 5 사용 예시 -2: 서비스 테스트
1. @SpringBootTest 어노테이션을 사용하여 테스트 : @SpringBootTest
💡 @SpringBootTest 어노테이션을 사용하여 테스트
- @SpringBootTest를 사용하면 애플리케이션 컨텍스트를 로딩하고 필요한 빈을 초기화하는 등 테스트에 필요한 설정과 의존성을 설정하는데 도움이 됩니다.
💡 @SpringBootTest
- 애플리케이션의 전체 컨텍스트를 로드하여 테스트할 수 있습니다. 이를 통해 실제 환경과 유사한 설정에서 테스트를 수행하고 각각의 컴포넌트가 상호작용하는 방식을 확인할 수 있습니다.
- 애플리케이션의 다양한 컴포넌트를 테스트할 수 있으며, 외부 서비스와의 상호작용, 데이터베이스 연동 등을 포함한 실제 환경에서의 동작을 확인할 수 있습니다.
💡 클래스에 @SpringBootTest 어노테이션을 선언하면 @Test을 수행하면서 아래와 같이 로컬 서버가 수행되면서 테스트가 진행되는 것을 확인할 수 있습니다.
1.1. 테스트 수행 구조
💡 테스트 수행구조
1. 클래스 내에 @SpringBootTest 어노테이션을 선언하였습니다. (*이는 @Test 어노테이션 수행직전에 수행이 됩니다)
2. 테스트를 시작하면 @BeforeAll 어노테이션을 통해 setUpBeforeClass() 함수가 수행됩니다.
3. @Test 어노테이션이 수행되기 직전에 로컬 서버가 실행이 되어 각각의 컨텍스트를 로드해 옵니다.
4. @Test 어노테이션을 통해 testIsNotNullCodeList() 함수가 수행됩니다.
5. 테스트를 종료하면서 @AfterAll 어노테이션을 통해 cleanUpAfterClass() 함수가 수행됩니다.
2.2. 코드 사용 예시
💡 코드 사용 예시
- 해당 코드에서는 CodeService를 주입받아서 값을 구성하여 서비스를 호출하는 테스트를 구성하였습니다.
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;
/**
* Please explain the class!!
*
* @author : lee
* @fileName : ServiceTests
* @since : 12/7/23
*/
@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);
}
}
2.3. 수행 결과
2. 기존에 구성된 서비스 테스트
💡 기존에 구성된 서비스 테스트하기
- 기존에 구성한 클래스나 인터페이스를 테스트하기 위해서 모두 다 서비스를 구성할 필요 없이 간단하게 구성이 가능합니다.
2.1. 클래스/인터페이스 파일명에 오른쪽 마우스키 - Go To - Test 선택
💡 클래스 파일명 또는 인터페이스에 오른쪽 마우스키를 누르고 Go To - Test를 선택합니다.
2.2. 출력된 화면을 확인합니다.
💡 아래와 같이 팝업이 출력됩니다.
메뉴 | 설명 |
Testing library | 이는 프로젝트에서 사용되는 테스팅 프레임워크나 라이브러리를 의미합니다. 예를 들어 JUnit이나 TestNG와 같은 것들이 있습니다. |
Class Name | 테스트를 생성하려는 클래스의 이름입니다. |
Superclass | 생성된 테스트 클래스가 위치할 패키지입니다. (따로 수행하지 않으면 test 폴더에 패키지 명을 가지와서 생성이 됩니다) |
Destination package | 버튼은 입력한 정보를 기반으로 테스트 클래스를 생성합니다. - @setUp/@Before : 매번 @Test 수행 전에 수행될 메서드 사용여부 - @tearDown/ @After : 매번 @Test 수행 이후에 수행될 메서드 사용여부 |
Generate | 입력한 정보를 기반으로 테스트 클래스를 생성합니다. |
Generate test method for | 클래스의 특정 메소드에 대한 테스트 메소드를 생성할 수 있도록 합니다. |
2.3. 아래와 같이 선택하여 테스트 파일을 만듭니다.
2.4. 아래 경로에 파일이 생성되었습니다.
2.5. 만약 메서드를 추가하여 테스트를 하고 싶으면 Go To - Test를 선택하여 추가할 수도 있습니다.
2.6. 테스트가 잘되었음을 확인하였습니다.
💡 [참고] Spring Boot 환경에서 JUnit5를 이용하기 위한 관련 글들입니다.
분류 | URL |
JUnit 5 이론 및 구성 요소 | https://adjh54.tistory.com/341 |
JUnit 5 환경구성 및 활용예제 | https://adjh54.tistory.com/342 |
JUnit 5 + Mockito 이론 및 활용예제 | https://adjh54.tistory.com/346 |
JUnit 5 + MockMvc 이론 및 활용예제 | https://adjh54.tistory.com/347 |
Assertions API |
오늘도 감사합니다. 😀
반응형
'Java > Testing' 카테고리의 다른 글
[Java] Spring Boot JUnit5 이해하기 -3: @RepeatedTest, @ParameterizedTest를 이용한 반복 테스트 (0) | 2024.07.28 |
---|---|
[Java] Spring Boot MockMvc 이해하기 : 테스트 흐름 및 사용예제 (0) | 2023.12.15 |
[Java] Spring Boot Mockito 이해하기 : 테스트 흐름 및 사용예시 (0) | 2023.12.14 |
[Java] Spring Boot JUnit5 이해하기 -1 : 이론 및 구조 (1) | 2023.12.07 |