15.4.3. 중복된 테스트 프롬프트 및 검증 로직의 모듈화(Modularity)

15.4.3. 중복된 테스트 프롬프트 및 검증 로직의 모듈화(Modularity)

테스트 코드(Test Code)는 프로덕션 시스템의 거울이다. 그러나 많은 데이터 과학자나 AI 엔지니어들이 프롬프트를 미세 조정(Fine-tuning)하고 실험하는 데에만 집중한 나머지, 테스트 스크립트 작성 시 DRY(Don’t Repeat Yourself) 원칙을 심각하게 위반하는 경향이 있다.

LLM을 검증하는 오라클 시스템에서 코드의 중복(Duplication)은 곧 비용의 중복이자 지식(Knowledge) 결합도의 비대화를 뜻한다. 수백 개의 테스트 케이스마다 시스템 프롬프트(System Prompt)가 복사 및 붙여넣기(Copy-Paste) 되어 있거나, JSON 구문을 파싱하는 무명 함수(Lambda)가 산재해 있다면, 프롬프트 엔지니어링의 미세한 변경 한 번이 수천 줄의 테스트 코드 수정을 강제하는 재앙으로 이어진다. 본 절에서는 이러한 테스트 난맥상을 해결하기 위한 계층적 모듈화(Hierarchical Modularity) 아키텍처를 제시한다.

1. 지식의 파편화 지표 식별

모듈화를 시작하기 전, 현행 오라클 시스템 내에서 중복이 발생하고 있는 구역을 식별해야 한다. AI 테스팅 환경에서 가장 흔히 발견되는 중복 지점은 다음과 같다.

  1. 시스템 프롬프트 주입부: “너는 친절한 금융 상담 챗봇이야. 항상 존댓말을 써야 해“와 같은 지시어 집합이 각 유닛 테스트마다 하드코딩되어 나타난다.
  2. API 호출 및 오류 처리(Retry/Backoff) 로직: LLM의 응답 지연(Latency)이나 Rate Limit 초과(HTTP 429) 에 대응하기 위한 지수적 백오프(Exponential Backoff) 로직이 테스트 함수마다 중복 작성되어 있다.
  3. 반복되는 후처리 패턴: 마크다운 블록 태그(json ... )를 제거하거나, 문자열의 양끝 공백을 자르는(Strip) 원시적인 전처리 코드가 산재해 있다.

2. 테스트 환경의 계층적 모듈화 설계

테스트 코드의 모듈화는 일반 백엔드 시스템 못지않게 정교한 클린 아키텍처(Clean Architecture) 원칙을 따라야 한다. LLM 호출, 데이터 정제, 그리고 검증 로직을 각각의 추상화된 계층으로 격리해라.

graph TD
subgraph Data Layer [데이터 계층]
A[Fixture: System Prompts] -->|주입| C
B[Fixture: User Test Cases] -->|주입| C
end

subgraph Execution Layer [추론 계층]
C[LLM Client Facade] -->|Rate Limit / Backoff 캡슐화| D(Raw Response)
end

subgraph Parsing Layer [전처리 계층]
D --> E{Response Parsers}
E -.->|파싱 로직 모듈화| F(Markdown Stripper)
E -.->|파싱 로직 모듈화| G(JSON Extractor)
E -.->|파싱 로직 모듈화| H(Length Truncator)
end

subgraph Oracle Layer [검증 계층]
F --> I[Oracle Base Interface]
G --> I
H --> I

I --> J(Regex Validations Module)
I --> K(Semantic Evaluators Module)
end

style Execution Layer fill:#f9f9f9,stroke:#666,stroke-width:2px,stroke-dasharray: 5 5
style Oracle Layer fill:#e6f7ff,stroke:#1890ff,stroke-width:2px

2.1 추론 전(Pre-inference) 모듈화: Fixture와 Facade

테스트 프레임워크(예: pytestconftest.py)가 제공하는 픽스처(Fixture) 기능을 십분 활용하여 시스템 프롬프트와 메타데이터를 통합 관리해라. 또한 LLM 벤더(OpenAI, Anthropic 등)의 API 스펙에 의존하는 코드를 LLM Client Facade라는 단일 클래스 내로 캡슐화함으로써, 테스트 코드는 오직 “질문(Q)을 던지고 응답(R)을 받는다“는 행위에만 집중하도록 만들어야 한다.

2.2 검증(Verification) 모듈화: Assertion 라이브러리 구축

각 개발자들이 제각각의 방식으로 assert문을 작성하는 것을 금지해라. 팀 차원에서의 검증 모듈, 즉 맞춤형 오라클 라이브러리(Custom Oracle Library)를 구축해야 한다.
예를 들어 assert_json_schema_matches(response, schema)assert_no_toxic_language(response)와 같이 의미가 뚜렷하게 명명된(Well-named) 함수 모음을 사용하도록 컨벤션화하면, 검증 로직 자체에 결함이 발생했을 때 단 하나의 모듈만 수정하면 전체 테스트 스위트를 구제할 수 있다.

3. 매개변수화 테스트(Parameterized Testing)의 적용

모듈화의 꽃은 코드 중복을 배열 루프(Array Loop) 하나로 대체하는 매개변수화 테스트이다. 오라클이 검증해야 할 ’쿼리와 정답 쌍’을 소스 코드 밖의 JSON이나 YAML 파일로 분리하고, 테스트 엔진은 이 독립된 레코드를 순회하며(iterate) 검증 함수를 재사용 파이프라인으로 돌려라. 이는 향후 Q/A 엔지니어나 도메인 전문가들이 코딩을 몰라도 데이터 파일만 수정하여 테스트를 확장(Scale-out)할 수 있게 만드는 비즈니스 생태계적 혁신을 동반한다.

4. 소결

파편화된 테스트 스크립트는 프로젝트에 ’깨진 유리창(Broken Windows)’을 양산한다. 중복된 프롬프트를 픽스처(Fixture)로 격리하고, 호출 로직을 파사드(Facade) 아키텍처 뒤로 숨기며, 난해한 검증식들을 직관적인 Assertion 모듈로 병합해라. 이러한 철저한 모듈화야말로, 수만 개의 엣지 케이스를 테스트 스위트 내로 집어넣고도 시스템의 형상 관리 구조가 무너지지 않도록 버텨주는 가장 강력한 기둥이다.