표준입출력 리다이렉션 (테스트 환경에서 어떻게 활용할 수 있을까?)

sobaman·2024년 11월 22일
0

Java

목록 보기
2/10

리다이렉션(Redirection)이란? 말 그대로 방향을 변경하는 것을 의미.

본래 표준 입력이란 키보드로 직접 받아오고
표준 출력은 이를 화면에 그대로 출력되는 것을 말하는데,

키보드로 표준 입력을 받거나 화면으로 표준 출력을 하는 것이 아닌
사용자의 마음대로 입력, 출력을 재지정하겠다는 말이다.

대표적으로 파일로 표준 입력을 받고 파일로 표준 출력을 받는 등의 행위가 이에 속한다.

자바에선 표준 입출력을 지원하는 도구들이 존재한다.

System.in 은 자바에서 표준 입력을 나타내며 InputStream 로 반환 → 바이트 스트림으로 처리

System.out 은 자바에서 표준 출력을 나타내는 PrintStream 로 반환 → 문자 스트림으로 처리

이 표준 입출력을 가로채서 리다이렉션 하는 기능들 역시 존재한다.

System.setIn() 에 데이터를 입력하면 System.in 에 해당 데이터가 리다이렉션 되며,

System.setOut() 에 데이터를 입력하면 System.out 에 해당 데이터가 리다이렉션 된다.

원하는 파일을 System.setIn() 으로 리다이렉션 하려면 아래와 같이 사용하면 된다.

public class Main {
    public static void main(String[] args) throws IOException {
		    // 가로채서 System.in 에 해당 파일이 주입
			  System.setIn(new FileInputStream("원하는 파일 경로"));
			  BufferedReader = reader = new BufferedReader(new InputStreamReader(System.in));
			  reader.leadLine()
    }
}

매개변수로 데이터를 받아와 원하는 데이터를 주입하려면

아래와 같이 Scanner 를 만들어 이용하는 것이 더 좋은 방법일 수 있다.

// 입력
public static Scanner genScanner (final String input) {
		final InputStream in = new ByteArrayInputStream(input.getByte();
		return new Scanner
}

// 출력
public static ByteArrayOutputStream setOutToByteArray() {
		final ByteArrayOutputStream output = new ByteArrayOutputStream();
		System.setOut(new PrintStream(output));
		return output;
}

// setOutToByteArray 메서드 사용 후 정리, 다시 정상화 작업
public static void clearSetOutToByteArray(final ByteArrayOutputStream output) {
    System.setOut(new PrintStream(new FileOutputStream(FileDescriptor.out)));
    try {
        output.close();
    } catch (IOException e) {
        throw new RuntimeException(e);
    }
}
  • InputStream 은 바이트 스트림 단위로 처리된다 그랬으니 String → Byte 로 변환해주는 작업 필요

Scanner 를 이용하는 방식과
System.setIn() + BufferedReader 를 조합하여 사용하는 방식은
각각의 장단점이 존재한다.

항목Scanner 이용 방식System.setIn + BufferedReader 방식
편리성Scanner는 공백으로 구분된 단어 단위 또는 숫자 읽기 등 고수준 입력 처리 가능BufferedReader는 한 줄씩 읽기 등 문자 스트림에 적합
표준 입력 변경 여부표준 입력 변경 없음System.setIn으로 실제 표준 입력을 변경
테스트 시 의존성독립적 (표준 입력 변경 없이 메모리에서 동작)표준 입력을 변경하므로 테스트 후 복원이 필요

그러면 실제 테스트에서 어떤 식으로 사용될까?


class Test {
    AppConfig appConfig = new AppConfig();

    @Test
    @DisplayName("등록 명령 정상 작동")
    void register_test() {

        ByteArrayOutputStream output = TestUtil.setOutToByteArray();
        Scanner scanner = TestUtil.genScanner(
                """
                        등록
                        명언1
                        사람1
                        종료
                        """
        );

        appConfig.wiseSayingController(scanner).run();
        String result = output.toString().trim();

        assertTrue(result.contains("명언이 등록되었습니다."));

        TestUtil.clearSetOutToByteArray(output);

    }

여기서 중요한건 입출력 리다이렉션을 Scanner 호출보다 먼저 해줘야한다.

Sysyem.setOut() 은 전역 설정으로, 이를 호출하면 이후 발생하는 모든
System.out.printIn() 출력이 ByteArrayOutputStream 로 리다이렉션된다.
Scanner 가 먼저 실행되면 System.out 에 대한 리다이렉션 설정이 제대로 이루어지지 않는다.

  1. 작동하는 흐름을 파악하고 미리 정상 출력이 예상되는 입력값들을 주입
  2. 리다이렉션된 결과값을 가져온 뒤 테스트 진행
profile
백엔드 공부 정리 블로그

0개의 댓글