Junit은 Java에서 독립된 단위테스트를 지원해주는 프레임워크이다.
단위 테스트? (Unit Test)
특정 소스코드의 모듈이 의도한대로 잘 작동하는지 검증하기 위함
Spring에서 단위 테스트는 Spring Container에 올라와있는 Bean을 테스트하는 것
@Test, @BeforeEach 와 같은 직관적인 애노테이션을 사용해 테스트의 구조와 생명주기 관리 가능assertEquals(),assertTrue(), assertNotNull()과 같은 단언 메서드를 제공해 테스트 결과가 예상과 일치하는지 확인 가능| 애노테이션 | 설명 |
|---|---|
@Test | 이 메서드가 테스트 케이스임을 나타냄 → 테케 맨 위에 명시 필수 |
@DisplayName(”설명”) | 테스트 클래스나 메서드에 대한 설명을 보기 쉽게 저장 |
@AfterEach | 각각의 @Test 실행된 후 실행되어야 함 |
@BeforeEach | 각각의 @Test 실행 전 먼저 실행되어야 함 |
@AfterAll | 현재 클래스의 모든 @Test 메서드가 실행된 후 마지막으로 한 번만 실행 |
@BeforeAll | 현재 클래스의 모든 @Test 메서드 중 최초로 한 번만 실행 |
@Disabled | 특정 테스트를 일시적으로 비활성화할 때 사용 |
@Nested | 관련있는 테스트들을 하나의 중첩 클래스로 묶어 계층 구조로 만들 때 사용 다른 클래스 안에서 또 다른 테스트 가능 |

크게 클래스 레벨과 메서드 레벨로 나뉜다.
클래스 레벨 설정 (1번만 실행)
@BeforeAll을 사용해 클래스 전체에서 딱 한번 실행테스트 메서드 레벨 (각 테스트마다 반복)
@BeforeEach@Test가 실행되기 직전에 항상 호출됨@Test@AfterEach@Test 메서드가 실행된 직후에 항상 호출 (테스트 성공/실패 여부 관계없이 실행됨)@BeforeEach에서 사용한 자원이나 데이터를 정리해 다음 테스츠에 영향을 주지 않도록클래스 레벨 정리 (1번만 실행)
@AfterAll을 사용해 모든 테스트 완전히 종류된 후 마지막에 딱 한번 실행.@BeforeAll에서 설정한 DB 연결 등 해제pom.xml or build.gradle 파일에 의존성 주입 → refresh 필수<dependencies>
<dependency>
<groupId>org.junit.jupiter</groupId>
<artifactId>junit-jupiter-api</artifactId>
<version>5.10.2</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.junit.jupiter</groupId>
<artifactId>junit-jupiter-engine</artifactId>
<version>5.10.2</version>
<scope>test</scope>
</dependency>
</dependencies>
2. 테스트할 클래스 작성 (src/main 폴더에)
간단히 이메일과 나이를 검증하는 로직

package org.example;
public class MemberValidator {
/**
* 이메일 형식이 유효한지 검증합니다. (간단한 '@' 포함 여부만 체크)
* @param email 검증할 이메일
* @return 유효하면 true, 아니면 false
*/
public boolean isValidEmail(String email) {
if (email == null) {
return false;
}
return email.contains("@");
}
/**
* 성인인지 검증합니다. (19세 이상)
* @param age 검증할 나이
* @return 성인이면 true, 아니면 false
*/
public boolean isAdult(int age) {
return age >= 19;
}
/**
* 유효하지 않은 이메일일 경우 예외를 발생시킵니다.
* @param email 검증할 이메일
*/
public void validateEmailOrThrow(String email) {
if (email == null || !email.contains("@")) {
throw new IllegalArgumentException("유효하지 않은 이메일 형식입니다.");
}
}
}
test/java 밑에 넣기)import org.example.MemberValidator;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.Test;
import static org.junit.jupiter.api.Assertions.*;
@DisplayName("회원 검증 로직 테스트")
class MemberValidatorTest {
private MemberValidator validator;
// 각 테스트가 실행되기 전에 MemberValidator 객체를 새로 생성합니다.
@BeforeEach
void setUp() {
validator = new MemberValidator();
System.out.println("새 Validator 객체 생성 완료");
}
@Test
@DisplayName("이메일에 '@'가 포함되면 성공한다")
void email_contains_at_sign_should_be_valid() {
// given (준비)
String email = "test@example.com";
// when (실행)
boolean result = validator.isValidEmail(email);
// then (검증)
assertTrue(result, "유효한 이메일은 true를 반환해야 합니다.");
}
@Test
@DisplayName("이메일에 '@'가 없으면 실패한다")
void email_without_at_sign_should_be_invalid() {
// given
String email = "testexample.com";
// when
boolean result = validator.isValidEmail(email);
// then
assertFalse(result, "유효하지 않은 이메일은 false를 반환해야 합니다.");
}
@Test
@DisplayName("나이가 19세 이상이면 성인으로 판단한다")
void age_19_or_more_should_be_adult() {
// given
int age = 20;
// when
boolean result = validator.isAdult(age);
// then
assertTrue(result);
}
@Test
@DisplayName("나이가 19세 미만이면 성인이 아니라고 판단한다")
void age_less_than_19_should_not_be_adult() {
assertFalse(validator.isAdult(18));
}
@Test
@DisplayName("유효하지 않은 이메일은 IllegalArgumentException 예외를 던진다")
void invalid_email_should_throw_exception() {
// given
String invalidEmail = "invalid-email";
// then
// assertThrows: 특정 예외가 발생하는지 검증합니다.
IllegalArgumentException exception = assertThrows(IllegalArgumentException.class, () -> {
// when
validator.validateEmailOrThrow(invalidEmail);
});
// 예외 메시지까지 검증할 수 있습니다.
assertEquals("유효하지 않은 이메일 형식입니다.", exception.getMessage());
}
}

작성한 테스트 코드가 잘 동작하는 것을 확인할 수 있다.