1.4.1.2 모킹(Mocking) 및 스터빙(Stubbing) 패러다임의 붕괴
전통적인 소프트웨어 테스트 기법에서 외부 시스템(External System)이나 데이터베이스를 테스트 대상 코드로부터 격리(Isolation)시키는 것은 가장 기본적인 대원칙이다. 엔지니어들은 테스트 환경의 결정론적 무결성을 보장하고 실행 속도를 높이기 위해 물리적 API 통신이나 복잡한 연산을 가짜 객체로 대체하는 모킹(Mocking)과 스터빙(Stubbing) 기법을 적극적으로 활용해 왔다.
하지만 대규모 언어 모델(LLM)이 핵심 컴포넌트로 개입하는 소프트웨어 2.0 환경에서는, 이 ’완벽한 격리’를 지향하는 모킹 패러다임 자체가 논리적 모순에 빠지며 그 효용성을 완전히 상실하게 된다.
1. 모킹(Mocking)의 기본 전제와 AI 아키텍처의 충돌
스터빙(Stubbing)은 “A라는 입력이 들어왔을 때, 무조건 B라는 고정된 데이터를 반환하라“고 테스트 프레임워크에 지시하는 행위이다. 이는 외부 모듈의 비즈니스 로직이 ’반드시 B를 반환할 것’이라는 결정론적 확신(Deterministic Certainty)이 있을 때만 의미를 갖는다.
그러나 AI 모델을 스터빙하는 것은 그 자체로 거대한 공학적 넌센스(Nonsense)가 된다. LLM이 반환하는 결괏값은 고정된 텍스트가 아니라, 수많은 파라미터(Temperature, Top-p 등)와 방대한 컨텍스트(Context)에 따라 실시간으로 변동하는 다차원 벡터의 근사치(Approximation)이다. 엔지니어가 테스트 환경에서 LLM의 API 호출을 가로채어(Intercept) ’완벽하게 포맷팅된 정답 JSON’을 무조건 반환하도록 스터빙한다면 다음과 같은 치명적인 문제가 발생한다.
- 실제 장애의 은닉(Masking Real Failures): 상용(Production) 환경에서 LLM은 환각(Hallucination)으로 인해 구조가 깨진 JSON이나 엉뚱한 설명을 반환할 수 있다. 하지만 스터빙된 환경은 항상 ’올바른 포맷’을 반환하므로, 이러한 잠재적인 파싱(Parsing) 에러나 예외 처리(Exception Handling) 로직의 결함을 전혀 검증하지 못한다.
- 프롬프트(Prompt) 유효성 검증 불가: 프롬프트 문구를 수정했을 때, 그 변경이 모델의 출력에 미치는 영향을 파악하는 것은 AI 앱 개발의 핵심이다. LLM API를 모킹하여 연결을 끊어버리면, 프롬프트 엔지니어링의 결과가 비즈니스 로직에 미치는 영향을 물리적으로 감지할 수단을 상실하게 된다.
2. 의미 없는 통과(Green Build)와 프로덕션 크래시(Production Crash)
결과적으로 LLM을 고정된 값으로 스터빙한 상태에서 진행되는 CI/CD(지속적 통합/지속적 배포)의 자동화 테스트 결과는 사실상 아무런 가치를 지니지 않는 ’거짓된 통과(Fake Green Build)’에 불과하다.
테스트 코드 내에서는 100%의 커버리지(Coverage)를 달성하며 성공적으로 통과(Pass) 단계에 도달하더라도, 실제 프로덕션 런타임(Runtime) 환경에 배포되어 진짜 비결정적 AI 엔진과 연결되는 순간, 시스템은 예기치 않은 데이터 형식 파괴로 인해 즉각적인 시스템 크래시(System Crash)를 일으킨다.
graph TD
subgraph Traditional_Mocking [전통적 스터빙의 이상적 환경]
A[테스트 코드] -->|ID=1 요청| B((Mock DB / API))
B -->|결정론적 고정값 반환| C{Assert: 예상 == 결과}
C -->|형식 보장| D[유효한 테스트 Valid Test]
end
subgraph AI_Stubbing_Contradiction [AI 모킹의 공학적 모순]
E[프롬프트 테스트 코드] -->|문맥 입력| F((Mock LLM))
F -.항상 정답 문자열 하드코딩 반환.-> G{Assert}
G -->|무조건 통과| H[거짓된 배포 승인 Fake Green]
H -.실제 프로덕션 배포.-> I((Real LLM Engine))
I -->|환각에 의한 1% 포맷 붕괴| J[실행 중단 예외 Runtime Exception]
J --> K[사일런트 페일러 및 서비스 마비]
end
style D fill:#e3f2fd,stroke:#1565c0,stroke-width:2px;
style J fill:#ffebee,stroke:#c62828,stroke-width:2px;
style K fill:#b71c1c,stroke:#fff,stroke-width:2px;
3. 결정론적 검증에서 확률적 필터링으로의 전환
이러한 위험성을 인지한 일부 엔지니어들은 LLM 프레임워크 자체를 역으로 무작위(Random)의 문장들을 뱉어내게끔 동적 모킹을 시도하기도 한다. 그러나 이렇게 되면 이번에는 assert 구문으로 검증을 수행할 기준점 자체가 완전히 소멸해 버리는 또 다른 딜레마에 부딪히게 된다. 무작위 문자열이 과연 우리의 비즈니스 로직을 통과해도 되는 ’정확한 값’인지 테스트 프레임워크가 판별할 수 없기 때문이다.
이러한 모킹과 스터빙 패러다임의 기계적인 붕괴는 단 하나의 결론을 향하고 있다. 언어 모델을 테스트 환경에서 기계적으로 격리시켜 결정론적으로 흉내 내려는 우회 전략을 과감히 버려야 한다는 것이다. 그 대신, 물리적인 비결정성을 있는 그대로 수용하고 실제 모델 파이프라인과 결합한 상태에서, 산출된 텍스트의 유효성과 진위(Truthfulness)를 ’의미론적(Semantically)’으로 보증하고 차단해 낼 강력한 **오라클(Test Oracle)**을 구축하는 것만이 신뢰성을 규명할 수 있는 유일한 공학적 실천 방안이다.