Day 31 - assertThat

haxxru log;·2026년 4월 14일
post-thumbnail

이 글은 2026년 04월 14일 작성된 글입니다.

오늘은 CLI 기반 명언 앱을 TDD 방식으로 구현하면서 테스트 환경 구성과 단계별 기능 흐름을 정리했다. 특히 TestUtil을 활용한 입출력 테스트와 단계별 요구사항을 중심으로 학습했다.


1. 프로젝트 요구사항 및 구조 이해

명언 앱은 CLI 환경에서 동작하며, 단계적으로 기능을 확장하는 구조로 설계된다.
등록, 목록, 삭제, 수정 기능을 기반으로 이후 파일 저장, 검색, 페이징까지 확장된다.

핵심 흐름

  • 명령어 입력 → 기능 수행 → 결과 출력
  • 명언은 id, content, author로 구성
  • id는 증가하며 재사용하지 않음

핵심

  • 기능은 단계별로 확장되며 점진적으로 구현된다.
  • 데이터는 리스트 → 파일 → DB 순으로 발전한다.

2. TDD를 위한 입출력 문제 해결

기존 Scanner(System.in) 방식은 테스트 자동화에 부적합하다.
따라서 문자열 기반 입력과 출력 캡처 방식으로 변경했다.

입력 처리

Scanner scanner = new Scanner("""
등록
현재를 사랑하라.
작자미상
""");

출력 처리

ByteArrayOutputStream out = TestUtil.setOutToByteArray();
System.out.println("출력 테스트");
String result = out.toString();

핵심

  • 문자열 입력을 통해 자동 테스트가 가능해진다.
  • 출력은 ByteArray로 받아 검증한다.

3. TestUtil 구현

테스트를 위해 공통 유틸 클래스를 직접 구현했다.

public class TestUtil {
    private static final PrintStream ORIGINAL_OUT = System.out;

    public static Scanner genScanner(String input) {
        return new Scanner(input);
    }

    public static ByteArrayOutputStream setOutToByteArray() {
        ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
        System.setOut(new PrintStream(byteArrayOutputStream));
        return byteArrayOutputStream;
    }

    public static void clearSetOutToByteArray() {
        System.setOut(ORIGINAL_OUT);
    }
}

핵심

  • 테스트 코드에서 입력/출력을 제어하기 위한 핵심 도구다.
  • TDD 환경 구축의 기반 역할을 한다.

4. AppTestRunner 도입

테스트 코드에서 반복되는 실행 로직을 줄이기 위해 AppTestRunner를 사용한다.

String out = AppTestRunner.run("""
등록
현재를 사랑하라.
작자미상
""");

핵심

  • 테스트 실행 로직을 공통화할 수 있다.
  • 테스트 코드가 훨씬 간결해진다.

5. TDD 사이클 적용

기능 구현은 항상 다음 흐름을 따른다.

  • red : 실패하는 테스트 작성
  • green : 테스트 통과 최소 구현
  • blue : 리팩토링

예시 (등록 기능)

assertThat(out)
    .contains("명언 :")
    .contains("작가 :")
    .contains("1번 명언이 등록되었습니다.");

핵심

  • 테스트를 먼저 작성하고 구현한다.
  • 작은 단위로 반복하면서 안정적으로 기능을 만든다.

6. 단계별 기능 구현 흐름

이번 학습에서 진행한 주요 단계는 다음과 같다.

주요 단계

  1. 종료 기능 구현
  2. 등록 기능 구현
  3. 등록 시 ID 출력
  4. ID 자동 증가
  5. 목록 출력
  6. 삭제 기능
  7. 예외 처리
  8. 수정 기능

핵심

  • 기능을 한 번에 구현하지 않고 단계별로 쪼개서 진행한다.
  • 각 단계마다 테스트를 통해 검증한다.

7. 테스트 코드 구조

테스트는 명령어 단위로 작성한다.

@Test
@DisplayName("등록")
void t1() {
    String out = AppTestRunner.run("""
    등록
    현재를 사랑하라.
    작자미상
    """);

    assertThat(out).contains("1번 명언이 등록되었습니다.");
}

핵심

  • 실제 사용자 입력 흐름과 동일하게 테스트한다.
  • 통합 테스트 방식으로 진행한다.

✅ 정리

  • CLI 명언 앱은 단계별로 기능을 확장하는 구조로 구현된다.
  • TDD를 적용하기 위해 입력과 출력을 문자열 기반으로 변경해야 한다.
  • TestUtil은 테스트 환경을 구성하는 핵심 유틸 클래스이다.
  • AppTestRunner를 사용하면 테스트 코드 중복을 줄일 수 있다.
  • TDD는 red → green → blue 사이클을 반복하며 진행한다.
  • 기능은 작은 단위로 나누고 테스트를 먼저 작성하는 것이 중요하다.
  • 테스트는 실제 사용자 입력 흐름과 동일하게 작성하는 것이 핵심이다.

0개의 댓글