테스트 코드를 진행하기 위해서는 자바 표준 입출력의 리다이렉션을 공부해야합니다
자바 표준 입출력이란?
System.in, System.out 같은 것을 말하는겁니다
아래에 제가 준비한 실습코드를 직접 타자치면서
어떻게 동작하는지 배워보시면 이해가 빠르게 될 겁니다
모니터에 출력되는 내용을 문자열로 받을 수 있도록 테스트 코드를 작성해봤습니다.
이 코드는 실제 출력을 변경하지 않고 별도의 문자열에 저장합니다.
private static void lab4() {
System.out.println("--시작4--");
// ByteArrayOutputStream을 생성하여 출력 내용을 메모리 내에서 저장할 수 있게 합니다.
ByteArrayOutputStream output = new ByteArrayOutputStream();
// System.out을 output이라는 PrintStream으로 set한다.
System.setOut(new PrintStream(output));
// .println() 호출 시 실제 콘솔이 아닌 output에 문자열이 저장됨
System.out.println("안녕하세요");
System.out.println("반갑습니다");
// System.out을 원래의 표준 출력 스트림(콘솔)으로 복원합니다.
System.setOut(new PrintStream(new FileOutputStream(FileDescriptor.out)));
// 원래의 System.out을 사용하여 종료 메시지를 콘솔에 출력합니다.
System.out.println("-- 끝4 --");
// ByteArrayOutputStream에 저장된 출력 내용을 문자열로 변환하여 콘솔에 출력합니다.
// 이를 통해 실제로는 화면에 출력되지 않았던 "안녕하세요"와 "반갑습니다"가 출력됩니다.
System.out.println("출력: " + output.toString());
// ByteArrayOutputStream 리소스를 해제하여 메모리 누수를 방지합니다.
try {
output.close();
} catch (IOException e) {
// IOException 발생 시, 런타임 예외로 래핑하여 던집니다.
throw new RuntimeException(e);
}
}
}
콘솔 출력값
--시작4--
-- 끝4 --
출력: 안녕하세요
반갑습니다
키보드 입력을 미리 준비된 문자열로 대체하여 테스트할 수 있도록 작성한 코드입니다.
private static void lab2(){
// 입력값을 미리 정의 합니다
InputStream in = new ByteArrayInputStream("안녕\n잘가".getBytes());
// 스캐너에 InputStream을 넣고 스캐너 객체로 만듭니다
Scanner scanner = new Scanner(in);
// 콘솔에 출력
System.out.println("명령2) ");
// 스캐너에 줄바꿈을 기준으로 첫번째 입력인 안녕을 가져옴
String cmd = scanner.nextLine().trim();
// 안녕 출력
System.out.println("입력한 명령: " + cmd);
System.out.println("명령2) ");
// 스캐너에 안녕 다음으로 입력된 잘가를 가져옴
cmd = scanner.nextLine().trim();
// 잘가 출력
System.out.println("입력한 명령: " + cmd);
}
콘솔 출력값
명령2)
입력한 명령: 안녕
명령2)
입력한 명령: 잘가
위 방법들을 응용하면
사용자가 콘솔로 볼 수 있는 문자열과 사용자가 콘솔에 입력하는 데이터를
별도의 스트림에 저장해서 테스트 코드에서 활용할 수 있습니다.
아래의 코드는 입출력 모두 응용해서 만든 테스트 코드입니다.
@Test
@DisplayName("registerWiseSay 호출 시 성공적으로 명언이 등록된다.")
void testRegisterWiseSay_Success() {
// Arrange: 테스트 환경 설정
String simulatedInput = "멋진 명언\n위대한 작가\n"; // 사용자 입력 시뮬레이션 (명언과 작가)
InputStream originalIn = System.in; // 기존 표준 입력(System.in) 백업
System.setIn(new ByteArrayInputStream(simulatedInput.getBytes())); // 표준 입력 리다이렉션
ByteArrayOutputStream outputStream = new ByteArrayOutputStream(); // 출력 캡처를 위한 스트림 생성
PrintStream originalOut = System.out; // 기존 표준 출력(System.out) 백업
System.setOut(new PrintStream(outputStream)); // 표준 출력 리다이렉션
WiseSayingController controller = new WiseSayingController(); // 테스트 대상 컨트롤러 객체 생성
// Mocking: WiseSayingService를 Mock 객체로 생성
WiseSayingService mockService = mock(WiseSayingService.class);
// ReflectionTestUtils를 사용하여 WiseSayingController의 private 필드(wiseService)에 Mock 객체 주입
ReflectionTestUtils.setField(controller, "wiseService", mockService);
int generatedId = 1; // Mock 서비스가 반환할 ID 값 설정
// Mocking: Mock 서비스가 register 메서드 호출 시 "멋진 명언"과 "위대한 작가"를 받아 generatedId를 반환하도록 설정
when(mockService.register("멋진 명언", "위대한 작가")).thenReturn(generatedId);
// Act: 테스트 대상 메서드 호출
controller.registerWiseSay();
// Assert: 테스트 결과 검증
// Mock 서비스의 register 메서드가 올바른 파라미터로 한 번 호출되었는지 검증
verify(mockService, times(1)).register("멋진 명언", "위대한 작가");
// 출력 메시지 검증: 리다이렉션된 출력에 기대 메시지가 포함되었는지 확인
String capturedOutput = outputStream.toString().trim();
assertTrue(capturedOutput.contains("1번 명언이 성공적으로 등록되었습니다."));
// Cleanup: 테스트 환경 복구
System.setIn(originalIn); // 표준 입력(System.in) 복구
System.setOut(originalOut); // 표준 출력(System.out) 복구
}
표준 입출력 파트는 봐도봐도 어려운 것 같아요 ㅜ 명언앱 TDD로 다시 만들때엔 혼자 더 자세히 봐야겠습니다😅 오늘도 좋은 내용 잘 보고 갑니다