작성한 코드가 의도대로 동작하고 예상치 못한 문제가 없는지 확인할 목적으로 작성하는 코드이다.
유지보수의 용이성, 코드 수정에 있어서의 편의성 등의 장점이 있다.
테스트 코드는 test 디렉토리에서 작업 한다.
테스트 코드에는 대표적으로 AAA패턴과 given-when-then 패턴이 존재한다.
두 패턴은 구성 측면에서는 동일하지만 given-when-then 패턴이 사람이 읽기 더 쉽다.
- AAA 패턴
테스트 코드를 아래 3단계 순서로 구분하는 것을 말한다.
- Arrange(준비)
테스트를 실행하기 전에 필요한 것들을 준비한다. 예를 들어, 객체를 생성하거나, Mock 객체를 만들거나, 테스트 전에 호출되어야 할 API들을 호출하는 것들을 의미한다.
- Act(실행)
테스트 코드를 실행한다.
- Assert(단언)
실행한 코드가 예상한대로 동작했는지 확인한다. assertTrue(), assertThat() 등의 코드들이 해당한다.
Given
테스트 실행을 준비하는 단계
When
테스트를 진행하는 단계
Then
테스트 결과를 검증하는 단계
- Given-When-Then 패턴 테스트 코드 예시
스프링 부트는 애플리케이션을 테스트하기 위한 도구와 애너테이션을 제공한다.
spring-boot-starter-test 스타터에 테스트를 위한 도구들이 존재한다.
- 스프링 부트 스타터 테스트 목록 (JUnit과 AssertJ를 가장 많이 사용)
- JUnit : 자바 프로그래밍 언어용 단위 테스트 프레임워크
- Spring Tset & Spring Boot Test : 스프링 부트 애플리케이션을 위한 통합 테스트 지원
- AssertJ : 검증문인 어설션을 작성하는 데 사용되는 라이브러리
- Hamcrest : 표현식을 보다 이해하기 쉽게 만드는 데 사용되는 Matcher 라이브러리
- Mockito : JSON용 어설션 라이브러리
- JsonPath : JSON 데이터에서 특정 데이터를 선택하고 검색하기 위한 라이브러리
JUnit은 자바 언어를 위한 단위 테스트 프레임워크이다.
단위 테스트
: 작성한 코드가 의도대로 작동하는지 작은 단위(메소드)로 검증하는 것을 의미한다.
- JUnit의 특징
- 테스트 방식을 구분할 수 있는 애너테이션을 제공.
- @Test 애너테이션으로 메소드를 호출할 때마다 새 인스턴스를 생성, 독립 테스트 가능.
- 예상 결과를 검증하는 Assertion Methods 제공.
- 사용 방법이 단순하고 테스트 작성시간이 적다.
- 자동 실행, 자체 결과를 확인하고 즉각적인 피드백을 제공.
- Assertion Methods
Assert method는 org.junit.jupiter.api.Assertions 라는 클래스에 static으로 존재하고, 이를 활용하여 단위 테스트를 진행 할 수 있다.
Assert method는 테스트의 성공여부에 따라 AssertionError를 throw한다.
JUnit은 테스트끼리 영향을 주지 않도록 각 테스트를 실행할 때마다 테스트를 위한 실행 객체를 만들고 테스트 종료 시 실행 객체를 삭제한다.
테스트가 끝나면 콘솔창에 테스트 결과가 표시된다.
단, 성공여부, 테스트 케이스의 이름, 테스트 실행 시간 정보를 확인하기 위해서는 체크 버튼을 눌러주어야 한다.
// JUnitCycleTest.java
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
전체 테스트를 시작하기 전에 처음 한번만 실행된다. 주로 데이터베이스를 연결하거나 테스트 환경을 초기화 할 때 사용된다. 해당 애너테이션은 전체 테스트 실행 주기에서 한번만 호출 되어야하기 때문에 메소드는 static으로 선언되어야 한다.
@BeforeEach
테스트 케이스를 시작 전 매번 실행된다. 테스트 메소드에서 사용하는 객체를 초기화 하거나 테스트에 필요한 값을 미리 넣을 때 사용될 수 있다. 각 인스턴스마다 메소드를 호출해야 하므로 static으로 선언되면 안된다.
@AfterAll
전체 테스트를 종료하기 전 매번 실행된다. 주로 데이터베이스 연결을 종료하거나 공통적으로 사용하는 자원을 해제할 때 사용된다. 전체 테스트 실행 주기에서 한번만 호출되어야 하므로 메소드는 static으로 선언되어야 한다.
@AfterEach
각 테스트 케이스를 종료 전 매번 실행된다. 테스트 이후에 특정 데이터를 삭제해야 하는 경우 사용될 수 한다. 각 인스턴스마다 메소드를 호출해야 하므로 static으로 선언되면 안된다.
- JUnit 흐름
Assertions.assertEquals(a+b,sum); // 기댓값과 비교값이 잘 구분이 안되는 Assertion 예
assertThat(a+b).isEqualTo(sum); // 가독성이 좋은 AssertJ 예
두번째 코드와 같이 AssertJ를 사용할 경우에는 a와 b를 더한 값이 sum과 같아야한다는 의미가 좀 더 명확하게 표현이 된다는 장점이 있다.
- 자주 사용되는 메소드들
- isEqualTo(A)
A 값과 같은지 검증
- isNotEqualTo(A)
A 값과 다른지 검증
- contains(A)
A 값을 포함하는지 검증
- doesNotContain(A)
A 값을 포함하지 않는지 검증
- startsWith(A)
접두사가 A인지 검증
- endWith(A)
접미사가 A인지 검증
- isEmpty()
비어있는 값인지 검증
- isNotEmpty()
비어있지 않은 값인지 검증
- isPostive()
양수인지 검증
- isNegative()
음수인지 검증
- isGreaterThan(1)
1보다 큰 값인지 검증
- isLessThan(1)
1보다 작은 값인지 검증
해당 글은 다음 도서의 내용을 정리하고 참고한 글임을 밝힙니다.
신선영, ⌜스프링 부트 3 벡엔드 개발자 되기 - 자바 편⌟, 골든래빗(주), 2023, 384쪽