dev-sohee 님의 블로그
코드의 신뢰도를 높이는 JUnit 단위 테스트 본문
테스트 없이 개발되는 애플리케이션은 없고 테스트를 안거친 코드는 존재 가치가 없다고 봐도 무방할 정도로 개발자와 테스트는 뗄레야 뗄 수 없는 관계입니다. 만약 애플리케이션을 개발 및 확장할 때 테스트를 안한다면 개발자가 예상치 못한 상황이 생겼을 때 시스템이 중단된다거나, 원래 잘되던 기능이 새로운 버전에서는 정상 동작을 안하는 등의 심각한 문제가 발생할 수 있습니다. 이 글에서는 이렇게 중요한 테스트를 쉽게 할 수 있도록 자바가 지원하는 도구인 자바 테스팅 프레임워크 JUnit에 대해 알아보겠습니다.
단위 테스트
작은 단위의 특정 코드에 대해 의도한 대로 잘 작동하는지 검증하는 것을 단위 테스트라고 합니다. 단위의 크기가 작을수록 테스트의 복잡성이 낮아지고, 테스트하려는 대상이 명확하여 그 대상에만 집중할 수 있기 때문에 가능하면 작은 단위로 쪼개서 테스트하는 것이 바람직합니다. 단위의 크기와 범위는 정해져 있지 않고, 충분히 하나의 관심에 집중해서 효율적으로 테스트할 만한 범위의 단위라고 생각하시면 됩니다.
단위 테스트 장점
- 단위 테스트는 해당 부분만 독립적으로 테스트하기 때문에 오류가 생겼을때 문제의 범위를 축소하여 빠르게 원인을 파악할 수 있습니다.
- 테스트 코드를 수시로 빠르게 돌리면서 조기에 문제점을 발견하고 수정할 수 있습니다.
- 기존 단위 테스트가 있으면 리팩토링을 할 때 기능이 깨지지 않았는지 확인할 수 있어 안심하고 기능을 제공할 수 있습니다.
#JUnit
JUnit은 자바로 단위 테스트를 작성하고 실행하기 위한 테스트 프레임워크입니다. 테스트 작성 시 자주 필요한 여러가지 부가 기능도 제공하기 때문에 자바 개발자가 가장 많이 사용하는 테스팅 기반 프레임워크입니다. 대부분의 자바 IDE는 JUnit 테스트를 손쉽게 실행할 수 있는 JUnit 테스트 지원 기능을 내장하고 있어 JUnit 테스트를 더욱 편리하게 활용할 수 있습니다.
JUnit 기능
- 단정 메서드(Assertions)
- 기본 단정: assertEquals(expected, actual), assertNotEquals(expected, actual), assertTrue(condition), assertFalse(condition), assertNull(object), assertNotNull(object) 등을 사용하여 테스트의 결과와 예상 결과가 일치하는지 판별할 수 있습니다.
- 예외 테스트: assertThrows(expectedType, executable)를 사용하여 특정 예외가 발생하는지 검증할 수 있습니다.
- 컨테이너 검사: assertArrayEquals(expectedArray, actualArray), assertIterableEquals(expectedIterable, actualIterable) 등을 사용하여 배열이나 컬렉션의 내용을 비교할 수 있습니다.
- 테스트 생명주기 관리
- 전처리 및 후처리: @BeforeEach, @AfterEach, @BeforeAll, @AfterAll 어노테이션을 사용하여 테스트 메서드 실행 전후에 필요한 작업을 설정할 수 있습니다.
- 조건부 실행
- 조건부 테스트 실행: @EnabledIf, @DisabledIf와 같은 어노테이션을 사용하여 조건에 따라 테스트를 실행하거나 비활성화할 수 있습니다.
- 테스트 구조화
- 테스트 클래스와 메서드: @Nested 어노테이션을 사용하여 테스트 메서드를 논리적으로 그룹화할 수 있습니다.
- 파라미터화된 테스트: @ParameterizedTest와 @ValueSource, @CsvSource 등 어노테이션을 사용하여 동일한 테스트 메서드를 다양한 입력값으로 실행할 수 있습니다.
- 테스트 결과 보고
- 테스트 결과: 테스트 실행 후 결과를 상세하게 보고하며, 실패한 테스트의 원인을 정확히 파악할 수 있도록 도와줍니다.
- 테스트 커버리지 체크
- 테스트 커버리지란 소스 코드의 얼마나 많은 부분이 테스트되었는지를 측정하는 지표입니다. 예를 들어, 코드의 80%가 테스트된 경우, "테스트 커버리지 80%"라고 말합니다. JUnit은 JaCoCo(Java Code Coverage)같은 커버리지 도구와 결합하여 커버리지를 결과를 리포트를 생성하고, 이를 통해 코드의 테스트 범위를 분석할 수 있습니다 .
#JUnit4 vs JUnit5
JUnit4와 JUnit5 모두 자바에서 단위 테스트를 작성하고 실행하는 데 사용되는 프레임워크이지만, JUnit5는 여러 가지 면에서 JUnit4를 확장하고 개선한 버전입니다. 두 버전의 주요 차이점은 다음과 같습니다.
1. 모듈화 및 아키텍처
JUnit4는 단일 라이브러리로 구성되어 있으며, 모든 기능은 하나의 JAR 파일에 포함되어 있습니다. JUnit5는 다음과 같이 구성되어 있습니다.
- JUnit Platform: 테스트 엔진을 위한 플랫폼으로, 다양한 테스트 프레임워크(예: JUnit 3, JUnit 4, TestNG)를 실행할 수 있는 기반을 제공합니다.
- JUnit Jupiter: JUnit 5의 주 테스트 엔진으로, JUnit 5의 새로운 프로그래밍 모델과 확장 모델을 제공합니다. 추가된 기능으로는 @TestFactory(동적 테스트), @RepeatedTest(반복 실행할 수 있는 테스트), @TestTemplate(반복적으로 실행되는 테스트 케이스의 기본 구조 정의) 등이 있습니다.
- JUnit Vintage: JUnit 4 및 JUnit 3의 테스트를 실행할 수 있는 엔진입니다. 기존 JUnit 4 테스트를 JUnit 5 플랫폼에서 실행할 수 있도록 지원합니다.
2. Annotations
JUnit5에는 JUnit4와 동일하게 사용되는 Annotation도 있고, JUnit4에는 없던 추가된 Annotation들도 있습니다.
3. JDK 요구사항
- JUnit4: Java5 이상
- JUnit5: Java8 이상
4. Assumptions
Assumptions는 테스트가 특정 조건에서만 실행되도록 제어할 때 사용되는 기능입니다.
JUnit4에서는 org.junit.Assume에 Assumptions 메서드가 포함되어 있고 다음의 5가지 기능을 제공합니다.
- assumeTrue(boolean condition): 조건이 true일 때만 테스트 실행
- assumeFalse(boolean condition): 조건이 false일 때만 테스트 실행
- assumeNotNull(Object... objects): 객체가 null이 아닐 때만 테스트 실행
- assumeThat(T actual, Matcher<? super T> matcher): Matcher 조건이 만족할 때만 테스트 실행
- assumeNoException: 주어진 코드 블록에서 예외가 발생하지 않을 때만 테스트 실행
JUnit 5에는 org.junit.jupiter.api.Assumptions에 Assumptions메서드가 포함되어 있습니다.
- assumeTrue(boolean condition): 조건이 true일 때만 테스트 실행
- assumeFalse(boolean condition): 조건이 false일 때만 테스트 실행
- assumeNotNull(Object... objects): 객체가 null이 아닐 때만 테스트 실행
- assumeThat(T actual, Matcher<? super T> matcher): Matcher 조건이 만족할 때만 테스트 실행
assumeNoException 메서드는 JUnit5에서는 제공되지 않으며, 예외가 발생하지 않는 테스트는 일반적인 예외 검증 메서드(assertDoesNotThrow)로 처리합니다.
테스트는 자동화해야 하고, 빠르게 실행할 수 있어야 하며 일관성 있는 결과를 제공해야 합니다. 그래서 많은 개발자들은 테스트 코드를 작성하고 검증하는데에 많은 시간과 에너지를 투자해야 했습니다. JUnit은 테스트 자동화와 품질 관리를 지원하는 도구로, 코드 품질을 높이고, 유지보수성을 개선시켜주는 스프링의 핵심적인 기능 중 하나입니다. 이를 통해 개발자는 비즈니스 로직 개발에 좀 더 집중할 수 있으며 개발 과정이 효율적으로 개선될 수 있습니다.
'spring' 카테고리의 다른 글
프록시의 세계: 다이나믹 프록시와 CGLIB의 차이 (0) | 2024.09.21 |
---|---|
효율적인 개발 방법론의 진화: TDD, BDD, DDD (0) | 2024.09.18 |
Spring의 3대 프로그래밍 모델 : 스프링 삼각형(IoC/DI, AOP, PSA) 2탄 (0) | 2024.08.31 |
Spring의 3대 프로그래밍 모델 : 스프링 삼각형(IoC/DI, AOP, PSA) 1탄 (1) | 2024.08.31 |