NsTest,Assertions는 우아한테크코스 미션에서 사용되는 테스트 API들이다.
사용하기 이전에 하나하나 톺아보자 !
2주차 자동차 경주 미션에는 위와 같은 테스트 파일이 먼저 제공되며 NsTest를 상속한 ApplicationTest가 구현되어 있다.
NsTest
Junit을 활용한 테스트 환경에서 콘솔 입출력을 테스트하기 위해 설계된 추상 클래스이다.
PrintStream standardOut;
테스트 수행 후, 시스템 출력(System.out)을 원래 상태로 복구하기 위해 기존 표준 출력 스트림을 저장한다.
OutputStream captor;
테스트 중 발생한 콘솔 출력을 임시로 저장하기 위한 스트림이다.
@BeforeEach protected final void init()
역할: 각 테스트 실행 전에 호출되어 초기화를 수행하며, 테스트 중 발생하는 출력 결과를 캡처하기 위해 표준 출력 스트림을 임시로 변경한다.
- 현재 표준 출력 스트림을 standardOut에 저장한다.
- 새로운 ByteArrayOutputStream 객체를 생성하고 이를 captor에 할당한다.
- 표준 출력(System.out)을 새롭게 생성된 PrintStream 객체(captor)로 변경한다.
@AfterEach protected final void printOutput()
역할: 각 테스트 실행 후 호출되어 출력 스트림을 원래 상태로 복구하고 테스트 결과를 출력하며, 테스트 완료 후 콘솔 출력 상태를 복구하고, 테스트 중 캡처된 결과를 콘솔에 출력한다.
- 표준 출력 스트림(System.out)을 초기 값(standardOut)으로 복원합니다.
- captor에 저장된 출력 내용을 output() 메서드를 통해 출력합니다.
output
역할: 테스트 중 캡처된 콘솔 출력 결과를 문자열로 반환하며, 테스트가 콘솔에 출력한 결과를 확인할 수 있도록 제공한다.
- captor.toString()을 호출하여 저장된 출력 내용을 문자열로 변환합니다.
- .trim()을 호출하여 문자열 앞뒤의 공백을 제거합니다.
run
역할: 입력 데이터를 설정하고 테스트 대상 프로그램의 main 메서드를 실행한다.
- command(args)를 호출하여 콘솔 입력 스트림(System.in)을 설정한다.
- 추상 메서드 runMain()을 호출하여 실제 프로그램 실행을 담당한다.
- 테스트 종료 후, Console.close()를 호출하여 리소스를 정리한다.
- 예외 처리: try-finally 블록을 사용하여 프로그램 실행 중 예외가 발생하더라도 리소스 정리가 보장된다.
command
역할: 콘솔 입력 데이터를 설정한다.테스트 중 실제 입력 대신 사전 정의된 데이터를 입력으로 사용할 수 있도록 한다.
- 입력 데이터(args)를 줄바꿈 문자(\n)로 연결하여 문자열로 만든다.
- 해당 문자열을 바이트 배열로 변환하여 ByteArrayInputStream에 저장한다.
- 표준 입력 스트림(System.in)을 새로 만든 ByteArrayInputStream으로 설정한다.
runMain
역할: 테스트 대상 프로그램의 실행 진입점을 정의하기 위한 추상 메서드이다.
구체 클래스에서 구현되며, 일반적으로 테스트 대상 프로그램의 main 메서드를 호출한다. 즉, Application.main인 애플리케이션 실행 함수를 빈 문자열 배열과 함께 실행한다.
runEception
역할: 예외 발생 가능성이 있는 테스트를 실행한다.테스트 중 예외가 발생하는 상황에서도 프로그램이 중단되지 않도록 한다.
- run(args)를 호출한다.
- NoSuchElementException 예외를 발생시키는 경우 이를 무시한다.
- 그 외의 예외는 그대로 터트리며 외부에서 assertThatThrownBy로 확인하도록 한다.
Assertions
JUnit과 Mockito를 활용하여 테스트를 지원하는 유틸리티 클래스로서 테스트에서 랜덤 값 생성 및 시간 관련 기능을 다루기 때문에, 테스트의 안정성을 위해 이러한 동작을 제어하고 검증하는 메서드를 제공한다.
static final Duration SIMPLE_TEST_TIMEOUT
간단한 테스트의 실행 시간 제한을 설정합니다.
static final Duration RANDOM_TEST_TIMEOUT
랜덤 값 또는 시간 의존적인 테스트의 실행 시간 제한을 설정합니다.
assertSimpleTest
역할: 간단한 테스트를 실행하며, 실행 시간이 SIMPLE_TEST_TIMEOUT을 초과하지 않도록 보장하며, 테스트가 너무 오래 걸리지 않도록 보장한다.
파라미터: Executable executable: 테스트 실행 로직(람다식이나 메서드 참조로 전달).
구현 : assertTimeoutPreemptively 메서드를 사용하여 시간 제한을 검증한다.
assertRandomNumberInListTest
역할: Randoms.pickNumberInList 메서드를 사용하는 테스트를 실행하며, 테스트 동안 반환값을 value와 values로 제한하며, 랜덤 값 생성을 제어하여 테스트의 예측 가능성을 높인다.
파라미터:
- Executable executable: 테스트 실행 로직.
- Integer value: 첫 번째 반환값.
- Integer... values: 이후 반환값들.
구현 : 내부적으로 assertRandomTest를 호출하여 동작을 캡슐화한다.
assertRandomNumberInRangeTest
역할: Randoms.pickNumberInRange 메서드를 사용하는 테스트를 실행하며, 반환값을 value와 values로 제한힌다.
구현 : assertRandomTest를 활용하여 랜덤 숫자 생성 동작을 모의(Mock)한다.
assertRandomUniqueNumbersInRangeTest
역할: Randoms.pickUniqueNumbersInRange 메서드를 사용하는 테스트를 실행하며, 반환값을 value와 values로 제한한다.
구현 : 동일한 방식으로 assertRandomTest를 호출한다.
assertShuffleTest
역할: Randoms.shuffle 메서드를 사용하는 테스트를 실행하며, 반환값을 value와 values로 제한힌다.
파라미터:
- List<T> value: 첫 번째 반환값 리스트.
- List<T>... values: 이후 반환 리스트.
구현:
- 제네릭 메서드로 구현되어, 다양한 타입의 리스트를 다룰 수 있다.
- assertRandomTest를 호출하여 Randoms.shuffle 동작을 제어한다.
assertRandomTest
역할: 랜덤 값 생성 메서드를 모의(Mock)하고 테스트를 실행하며, 랜덤 값 생성 동작을 테스트에서 제어 가능하게 만들어 테스트의 재현성을 보장한다.
파라미터:
- Verification verification: 모의(Mock)할 메서드를 정의하는 인터페이스.
- Executable executable: 테스트 실행 로직.
- T value: 첫 번째 반환값.
- T... values: 이후 반환값들.
구현:
- mockStatic(Randoms.class)를 호출하여 Randoms 클래스의 정적 메서드를 모의(Mock)한다.
- 반환값(value 및 values)을 설정한 후 테스트를 실행한다.
- 테스트 완료 후 MockedStatic 객체를 자동으로 닫아 리소스를 정리한다.
assertNowTest
역할: DateTimes.now 메서드를 사용하는 테스트를 실행하며, 반환값을 value와 values로 제한하며, 시간 관련 동작을 제어하여 특정 시간 시점에서의 테스트를 재현 가능하게 만든다.
파라미터:
- LocalDateTime value: 첫 번째 반환값.
- LocalDateTime... values: 이후 반환값들.
구현:
- mockStatic(DateTimes.class)를 호출하여 DateTimes.now 메서드를 모의(Mock)한다.
- 지정된 반환값을 설정하고 테스트를 실행한다.
- 테스트 완료 후 MockedStatic 객체를 닫는다.
assertTimeOutPreemptively
JUnit의 시간 제한(Time-out) 기능을 제공하며 지정된 timeout 기간 내에 executable이 실행을 완료해야 하며, 이를 만족하지 못하면 테스트가 실패한다.
- 시간 제한 적용:
- 지정된 시간(Duration) 안에 executable이 실행을 완료해야 한다.
- 실행이 시간 제한을 초과하면 테스트는 실패로 간주된다.
- 즉시 중단(Preemptive):
- 테스트 실행 중 시간이 초과되면 즉시 해당 실행을 중단한다.
- 이 점에서 일반 assertTimeout과 다릅니다. assertTimeout은 테스트가 완료될 때까지 기다린 후 시간 초과 여부를 확인하지만, assertTimeoutPreemptively는 초과 시 즉시 중단한다.
- 입력 파라미터:
- Duration timeout: 시간 제한 값입니다. 예를 들어 Duration.ofSeconds(5)는 5초를 의미한다.
- Executable executable: 실행할 테스트 로직입니다. 주로 람다식이나 메서드 참조로 전달된다.
- 기능 구현:
- 내부적으로 AssertTimeoutPreemptively.assertTimeoutPreemptively 메서드를 호출하여 기능을 제공하며 JUnit 라이브러리에서 제공하는 핵심 동작을 수행한다.
실제 예시 테스트에서 적용
게임 로직에서 랜덤 값이 주어졌을 때 결과를 검증하며, 랜덤 값이 4 이상일 경우 전진하고, 3 이하일 경우 정지하는 로직을 검증하려고 한다.
- assertRandomNumberInRangeTest 호출:
- 랜덤 숫자를 반환하는 Randoms.pickNumberInRange 메서드 호출을 제어한다.
- Verification: Randoms.pickNumberInRange(anyInt(), anyInt()) 호출이 모의(Mock)된다.
- 반환값 설정 첫 번째 호출 → MOVING_FORWARD (4), 두 번째 호출 → STOP (3)
- 람다식 실행 (() -> {...}):
- run("pobi,woni", "1") 호출:
- 입력값 "pobi,woni"은 두 명의 참가자를 나타낸다.
- 입력값 "1"은 게임 진행 라운드 수를 나타낸다.
- 내부적으로 게임 로직이 실행되며, MOVING_FORWARD와 STOP 값이 차례로 사용된다.
- run("pobi,woni", "1") 호출:
- 결과 검증:
- output() 메서드를 통해 프로그램 출력 결과를 가져온다.
- assertThat(output()).contains(...):
- "pobi : -" → pobi가 1회 전진한 결과.
- "woni : " → woni가 정지한 결과.
- "최종 우승자 : pobi" → pobi가 최종 우승자로 선정된 결과
결과 : 반환값: MOVING_FORWARD(4) → pobi 전진. STOP(3) → woni 정지. -> 출력 검증 성공
입력값이 잘못되었을 때, IllegalArgumentException이 발생하는지 검증한다.
- assertSimpleTest 호출:
- Executable로 전달된 람다식 실행을 수행하며, 실행 시간이 SIMPLE_TEST_TIMEOUT(1초)을 초과하지 않도록 검증한다.
- 람다식 실행 (() -> {...}):
- runException("pobi,javaji", "1") 호출:
- "pobi,javaji" → 참가자 이름으로 입력.
- "1" → 게임 진행 라운드.
- 입력 검증 로직에서 "javaji"가 유효하지 않은 이름으로 간주되어 IllegalArgumentException 발생.
- runException("pobi,javaji", "1") 호출:
- 예외 검증:
- assertThatThrownBy(...):
- 실행 중 발생한 예외를 포착한다.
- 예외가 IllegalArgumentException인지 확인한다.
- assertThatThrownBy(...):
결과 : 예외가 정상적으로 발생하면 테스트 성공.
'외부활동 > 우아한테크코스 [프리코스]' 카테고리의 다른 글
상수관리에 Enum은 필수적인가 ? (0) | 2024.11.01 |
---|---|
[우아한테크코스 7기] 프리코스 2주차 회고 (0) | 2024.10.29 |
자바의 정규표현식 톺아보기[Regex, Matcher, Pattern] 및 최적화 (0) | 2024.10.23 |
MVC 패턴 톺아보기 (0) | 2024.10.23 |
[우아한테크코스 7기] 프리코스 1주차 회고 (0) | 2024.10.23 |