2.1.2. 오라클의 3대 구성 요소: 생성기(Generator), 비교기(Comparator), 판정기(Verdict)

2.1.2. 오라클의 3대 구성 요소: 생성기(Generator), 비교기(Comparator), 판정기(Verdict)

테스트 오라클(Test Oracle)을 단일한 ’정답 파일’이나 단순한 if-else 검증문으로 인식하는 것은 소프트웨어 공학적 관점에서 매우 협소한 이해다. 복잡한 시스템의 상태(State)와 제어 흐름(Control Flow)을 신뢰성 있게 추적하고 검증하기 위해서, 현대의 자동화된 오라클 프레임워크는 논리적으로 분리된 3개의 핵심 구성 요소—생성기(Generator), 비교기(Comparator), 판정기(Verdict)—로 조립된 독립적인 서브시스템(Sub-system)으로 작동해야 한다.

본 절에서는 각각의 구성 요소가 담당하는 공학적 역할과 기능, 상호 동기화(Synchronization) 메커니즘을 상세히 분석하여 오라클 시스템의 내부 아키텍처를 해부한다.

1. 기대 결과 생성기 (Expected Result Generator)

생성기(Generator)는 SUT(System Under Test)가 특정 입력에 대해 도출해야 하는 논리적으로 ’완벽한 정답(Ground Truth)’을 합성해 내는 엔진이다. 테스팅 파이프라인에서 가장 구현하기 까다롭고 막대한 컴퓨팅 및 모델링 비용이 소모되는 계층이기도 하다.

  • 핵심 역할: 주어진 입력 데이터(Input Data)와 초기 시스템 상태(Initial State)를 바탕으로, 시스템 명세(Specification)나 도메인 지식(Domain Knowledge)에 기반하여 SUT와 완벽히 독립적인 방식으로 기대 결과(Expected Output) 를 추론 및 생성한다.
  • 구현적 한계점: 본질적으로 생성기를 완벽하게 구축한다는 것은 “테스트 대상(SUT)과 동일한 비즈니스 로직을 오류 없이 수행할 수 있는 또 다른 무결점 시스템을 개발하는 것“과 같은 모순(오라클 문제)을 내포한다. 때문에 실무에서는 수학적 모델, 결정 트리(Decision Tree), 단순화된 룰 엔진(Rule Engine), 혹은 과거의 안정적인 레거시 시스템(Pre-computed Legacy)을 역이용하는 방식으로 우회하여 생성기를 대체한다.

2. 결과 비교기 (Result Comparator)

비교기(Comparator)는 SUT에서 반환된 ’실제 결과(Actual Result)’와 생성기에서 도출된 ‘기대 결과(Expected Result)’ 간의 수학적, 의미적 동치성(Equivalence)을 판결하기 위한 연산 계층이다.

  • 핵심 역할: 단순히 A == B라는 얕은 수준의 데이터 일치 여부를 넘어, 도메인이 요구하는 오차 허용 범위(Tolerance Margin)와 데이터 무결성 검증 규칙을 적용하여 실질적인 로직의 부합 여부를 계산해 낸다.
  • 비교의 복잡성(Complexity of Comparison): 단순 스칼라(Scalar) 값의 비교는 연산이 단순하나, 복잡한 객체 그래프(Object Graph)나 대용량 JSON, 혹은 비결정적 로그(Log)가 섞인 결과를 대조할 때는 문제가 복잡해진다. 따라서 비교기에는 직렬화(Serialization), 허용 오차 함수(e.g., 부동소수점 \epsilon 차이 타협), 불필요한 메타데이터 필드를 탈락시키는 프로젝션(Projection) 메커니즘이 포함되어 비교 대상의 형태를 정규화(Normalization)해야 한다.

3. 최종 판정기 (Verdict Evaluator)

판정기(Verdict)는 비교기에서 도출된 세부적인 동치성 분석을 종합하여, SUT의 무결성 여부를 공식화하고 최종적으로 테스트 프레임워크에 결과를 릴레이하는 ’의사 결정권자’이다.

  • 핵심 역할: 테스트의 궁극적인 상태값(Pass, Fail, 혹은 Inconclusive)을 선고한다.
  • 상태 트리거(State Trigger): 판정기의 결과값은 독립적인 로깅(Logging) 정보로 끝나는 것이 아니다. CI/CD (지속적 통합/배포) 파이프라인과 직접적으로 연결(Coupling)되어, **“결함(Fail) 판단 즉시 진행 중인 빌드(Build) 파이프라인을 중단(Abort)하고 격리하라”**는 워크플로우 통제 권한을 가진다.
graph TD
    subgraph SUT Environment
        A[Input Data] -->|Execute| B[System Under Test]
        B --> C[Actual Result <i>R_a</i>]
    end

    subgraph Oracle Sub-system
        A -.->|Inject into Generator| D(생성기\nGenerator)
        D -->|Derived Truth| E[Expected Result <i>R_e</i>]
        
        C --> F{비교기\nComparator}
        E --> F
        
        F -->|Normalization &\nEquivalence Calculation| G([판정기\nVerdict])
        
        G -->|Matches: <i>R_a</i> \u2261 <i>R_e</i>| H[Pass: 통과]
        G -->|Mismatch: <i>R_a</i> \u2260 <i>R_e</i>| I[Fail: 결함]
    end
    
    I --> J[[CI/CD Pipeline Halt]]

    classDef component fill:#eef,stroke:#33c,stroke-width:2px;
    classDef output fill:#f9f,stroke:#c3c,stroke-width:1px;
    classDef alert fill:#fbb,stroke:#f00,stroke-width:2px;
    
    class D,F,G component;
    class C,E output;
    class I,J alert;

4. 소결: 모놀리식(Monolithic) 이해에서 모듈화(Modular)로

테스트 오라클을 생성기, 비교기, 판정기라는 세 가지 모듈로 해체하여 설계하는 관점은 소프트웨어 테스팅의 유지보수성(Maintainability)을 극대화하는 매우 중요한 공학적 결단이다.

만약 테스트 코드 내부에 정답의 텍스트, 비교하는 assertEquals 로직, 그리고 통과 후 처리 방식이 하나의 함수체(Monolithic Body) 안에 강박적으로 엉켜 있다면, 비즈니스 룰이 단 하나만 변경되어도 테스트 코드는 걷잡을 수 없는 수정을 피할 수 없게 된다.

추후 AI와 LLM 파이프라인을 검증할 때 이 3대 구성 요소의 분리성은 더욱 빛을 발한다. AI는 필연적으로 동일한 의미를 다른 단어 배열로 응답하므로(비결정성), ’생성기’는 그대로 두되, 문자열 비교기에서 ’의미론적 유사도(Semantic Similarity) 비교기’로 ’비교기’만을 교체 조립(Pluggable)시킴으로써 견고한 AI 오라클 시스템을 확장할 수 있기 때문이다.