어제 오늘 내일

[JUnit] TestRunner 동작 – 내부 구조 이해하기 본문

IT/JUnit

[JUnit] TestRunner 동작 – 내부 구조 이해하기

hi.anna 2026. 1. 13. 08:10

JUnit을 제대로 이해하려면 테스트가 실제로 어떻게 실행되는지, 즉 Test Runner(테스트 실행기)의 내부 동작 과정을 파악하는 것이 중요합니다.
겉으로는 “Run Test” 버튼을 누르는 것처럼 보이지만, 내부에서는 다음과 같은 복잡한 실행 흐름이 진행됩니다.

이번 글에서는 JUnit3 → JUnit4 → JUnit5로 이어지는 Test Runner의 진화 과정과 내부 동작 구조를 초보자도 이해할 수 있도록 정리합니다.

 

1. TestRunner란 무엇인가?

TestRunner(테스트 실행기)는 다음 역할을 수행하는 테스트 실행 엔진입니다.

  • 테스트 클래스 및 테스트 메소드 수집
  • @Before / @After 실행
  • 테스트 메소드 실행
  • 예외 및 실패 처리
  • 실행 결과(TestResult, Result, Listener) 수집

버전마다 구현 방식은 다르지만,
“테스트 실행 흐름을 제어하는 핵심 컴포넌트”라는 점은 동일합니다.

 

2. JUnit3 TestRunner 내부 흐름

JUnit3에서는 실제로 TestRunner라는 클래스가 존재했습니다.

실행 흐름 요약

  1. 테스트 클래스 로딩
  2. TestSuite 생성
  3. 각 TestCase 인스턴스 생성
  4. setUp() 호출
  5. 테스트 메소드 실행
  6. tearDown() 호출
  7. 실행 결과를 TestResult에 기록

예제

import junit.textui.TestRunner;

public class MyRunner {
    public static void main(String[] args) {
        TestRunner.run(MyTest.class);
    }
}

여기서 TestRunner.run()이 전체 테스트 실행을 조율하는 실제 엔진입니다.

 

3. JUnit4 Test Runner 구조: JUnitCore + Runner

JUnit4에서는 TestRunner가 두 부분으로 나뉩니다.

  • JUnitCore → 실행 요청을 받는 외부 실행기
  • Runner (예: BlockJUnit4ClassRunner) → 테스트 실행 로직 담당

즉,
JUnitCore = 실행 요청자,
Runner = 실제 실행 엔진(TestRunner 역할) 입니다.

내부 동작 흐름

  1. 테스트 클래스 분석(리플렉션)
  2. 테스트 메소드(@Test) 수집
  3. Runner 생성
  4. @BeforeClass 실행
  5. 테스트 메소드마다
    • @Before → @Test → @After
  6. @AfterClass 실행
  7. 결과(Result) 반환

JUnit4 실행 예제

Result result = JUnitCore.runClasses(UserTest.class);
System.out.println(result.getFailureCount());

 

 

4. JUnit5 Test Runner 구조: Launcher 기반

JUnit5에서는 TestRunner라는 이름이 사라졌지만, Launcher가 TestRunner 역할을 합니다.

실행 흐름

  1. Launcher가 테스트 탐색(Discovery)
  2. TestPlan(테스트 트리) 구성
  3. 테스트 실행 요청
  4. 각 테스트 실행
    • @BeforeEach
    • @Test
    • @AfterEach
  5. 결과를 TestExecutionListener에게 전달
  6. Summary 생성

예제

LauncherDiscoveryRequest request = LauncherDiscoveryRequestBuilder.request()
        .selectors(selectClass(MyTest.class))
        .build();

Launcher launcher = LauncherFactory.create();
launcher.execute(request);

비록 이름은 TestRunner가 아니지만,
Launcher가 테스트 실행기(Test Runner) 역할을 수행합니다.

 

5. 공통 실행 흐름 정리

JUnit 버전은 달라도 TestRunner의 핵심 동작은 변하지 않습니다.

  1. 테스트 수집 단계
    • 클래스 탐색
    • @Test 메소드 수집
  2. 테스트 실행 준비
    • BeforeAll 실행
    • 테스트 인스턴스 생성
  3. 테스트 실행
    • BeforeEach
    • Test
    • AfterEach
  4. 정리 단계
    • AfterAll 실행
  5. 결과 수집 & 보고
    • 성공/실패 개수
    • 실패 상세 정보
    • 실행 시간

TestRunner는 이 전체 흐름을 조율하는 중심 엔진입니다.

 

6. TestRunner 이해가 중요한 이유

  1. Before/After 동작 시점을 정확히 이해할 수 있음
  2. 테스트 실행 순서, 테스트 스위트 구성 원리를 파악 가능
  3. JUnit 버전별 테스트 실행 방식 차이를 이해
  4. SpringRunner, MockitoJUnitRunner 같은 Runner들이 어떻게 동작하는지 이해 가능
  5. CI 환경에서 테스트 자동화 시 문제 파악이 쉬움

 

7. 정리

  • TestRunner는 테스트 실행 흐름을 통제하는 엔진
  • JUnit3: TestRunner 클래스 직접 사용
  • JUnit4: JUnitCore + Runner 구조로 분리
  • JUnit5: Launcher API가 TestRunner 역할 수행
  • 내부 구조는 달라도 “Before → Test → After → 결과 수집” 흐름은 동일

TestRunner의 동작 방식을 이해하면 JUnit 전체 구조를 훨씬 쉽게 이해할 수 있습니다.

 

 

반응형
Comments