5.4. 목(Mocking) 객체와 페이크(Fake) 응답을 활용한 테스트 환경 격리

5.4. 목(Mocking) 객체와 페이크(Fake) 응답을 활용한 테스트 환경 격리

유닛 테스트(Unit Test)의 변하지 않는 절대적인 본질은, 외부의 변덕스러운 의존성(Dependency)을 칼같이 배제하고 단위 대상 코드를 바깥세상과 완전히 독립적으로 격리(Isolation)시킨 채, 통제된 실험실 환경에서 검증하는 데 있다. 그러나 AI 애플리케이션의 중추이자 핵심인 상용 프론티어 거대 언어 모델(LLM) API는 예측 불가능한 네트워크 지연(Latency), 호출할 때마다 피를 말리는 토큰당 과금(Cost), 그리고 온도(Temperature) 파라미터가 0이라도 미세하게 내재되어 있는 끔찍한 확률적 무작위성(Nondeterminism) 등 단위 테스트가 가장 혐오하고 기피하는 최악의 3대 악조건을 완벽하게 모두 갖춘 최악의 외부 의존성의 결정체다.

따라서 코드 파이프라인 로직의 아키텍처적 견고함을 증명하는 수백, 수천 개의 유닛 테스트 스위트(Test Suite)를 개발자의 깃허브 커밋(Commit) 푸시마다 쉴 새 없이 자동 실행해야 할 때, 매번 실제 OpenAI나 Anthropic의 비싼 API 엔드포인트를 무식하게 통신 호출하는 것은 회사 재정을 파산(Bankruptcy)으로 몰고 가는 지름길이자 CI/CD 파이프라인 빌드 타임의 목을 사정없이 조르는 병목 현상(Bottleneck)이다. 이러한 불확실하고 파괴적인 의존성의 사슬을 단호하게 끊어내고, 오직 비용이 0원인 결정론적 로직 위에 오라클 방어망을 구축하기 위해 필수적으로 도입해야 하는 핵심 데브옵스 전략이 바로 **‘목(Mocking) 객체와 페이크(Fake) 응답의 전략적 활용’**이다.

1. 외부 의존성의 완벽한 더블 대역(Test Double): 목(Mock) 객체 주입 아키텍처

소프트웨어 시스템에서 비싼 외부망 타사 LLM을 가장 우아하게 격리하고 코드를 대체할 수 있는 방법론 중 으뜸은, 파이썬 테스트 프레임워크가 자체 지원하는 강력한 모킹(Mocking) 객체를 파이프라인 중간에 주입(Injection)하는 것이다.
클라이언트와 직접 맞닿은 파이프라인을 감싸고 있는 백엔드의 래퍼(Wrapper) 클래스나 체인(Chain) 미들웨어를 테스트할 때, 우리의 관심사는 결코 *“바다 건너 데이터센터의 LLM 모델 자체가 얼마나 오늘 똑똑한가?”*가 전혀 아니다. 우리의 목적은 오직 *“AI가 응답 텍스트를 뱉고 스트림이 닫혔을 때, 우리 백엔드의 정규식 후처리 밸브나 데이터베이스 파이프가 톱니바퀴처럼 에러 없이 돌아가 파싱을 해내는가?”*를 기계적으로 검증하는 것이다. 이때는 외부 LLM 통신 호출 메서드 의존성 전체를 디자인 패턴 상의 ’가짜 껍데기 함수(Mock)’로 완전히 덮어씌워버려, 100% 통제된 결정론적 진공 상태를 강제해야 한다.

엔지니어는 파이썬의 unittest.mock 내장 모듈이나 pytest-mock과 같은 서드파티 라이브러리를 전투적으로 활용하여, 다음과 같은 양극단의 통제 변인 시나리오 스크립트를 하드코딩 설계한다.

  • [성공 시나리오 스텁(Stub) 강제 연출]: LLM이 아주 운 좋게 우리가 딱 원하는 이상적인 정답 JSON 딕셔너리 스키마 모양을 완벽하게 반환해 주었다고 행복하게 가정하는 ’하드코딩된 페이크(Fake) 응답 객체 텍스트’를 미리 가짜 메모리에 스텁(Stub)으로 등록해 둔다. 이 완벽한 스텁을 프레임워크에 통과시켜, 우리 시스템의 뒷단 Pydantic 후처리 파서(Parser) 로직이나 데이터베이스 ORM 저장 로직 단위가 KeyError나 파싱 예외 없이 깔끔하게 통과되어 영속화되는지 프론트/백엔드 코드를 0.01초 만에 눈부시게 검증한다.
  • [최악의 오류 시나리오 고의 강제 통신 단절 (Chaos Injection)]: 반대로, OpenAI의 실제 API 서버가 블랙프라이데이 트래픽 폭주로 갑자기 뻗어버리거나 5초 이상의 치명적 네트워크 타임아웃이 났을 때 우리 중계 시스템 파이프라인이 어떻게 우아하게 실패(Graceful Degradation)하고 사용자를 위로하며 복구하는지 테스트해야 한다. 이를 위해, Mock 객체 설정을 심하게 비틀어(Monkey Patching) 코드가 호출되는 즉시 무조건 자비 없이 HTTP 502 Bad Gateway 오류나 TimeoutException 네트워크 에러 스택 트레이스를 즉각 뿜어 발생시키도록 고의적으로 미세 조작한다.

오직 이러한 극단적인 모킹(Mocking) 진공 상태 위에서만 작동하는 가상의 섀도우 오라클은 시스템의 파라미터 세팅 값, 지수 백오프(Exponential Backoff) 리트라이(Retry) 요청 로직, 타 벤더 대체 모델로의 폴백(Fallback) 라우팅 체인지 메커니즘 등 우리 자체 애플리케이션의 뼈대인 ‘순수한 시스템적 인프라 방어력’ 결함을 100% 결정론적이고 반복 가능하게 확증하고 증명해 낸다.

2. 서버리스 환경의 자급자족 타협점: 초경량 로컬 페이크(Fake) 모델 운용

단순히 하드맵핑된 빈 껍데기 Mock 객체로 미리 짜둔 정적 응답 문자열만 똑같이 녹음기처럼 앵무새처럼 뱉어내게 하는 더미 수준을 이젠 아득히 넘어서서, 로직의 아주 기본적인 의미론적 정합성(Semantic Validation)마저 외부 네트워크 API 호출 없이 랩탑 CPU 만으로 수 밀리초 타임 내에 빠르게 유닛 테스트하고 싶은 하드코어 MLOps 엔지니어라면, 시스템 도커(Docker) 컨테이너 내부에 애초에 파라미터 수가 극도로 적은 ‘더미(Dummy)’ 형태의 로컬 소형 SLM(예: Qwen 0.5B 급 초소형 양자화 모델)을 테스트 전용 프레임워크 베이스로 직접 상주시켜 띄워 놓고 로컬 테스트 베드(Local Testbed)로 삼는 극단적 독립 방식도 있다.

이 강력하고 고도화된 아키텍처 방식은 수십 메가바이트 분량의 아주 얌전하고 저렴한 로컬 램(RAM) 메모리 자원만을 안전하게 소모하면서도, 진짜 외부 글로벌 대형 상용 LLM API가 개입하여 트래픽이 찰랑거릴 때와 동일한 HTTP 입출력 소켓 프로토콜 환경을 완벽하게 오프라인으로 모사할 수 있다. 이로써 회사는 외부 클라우드 프로바이더 사업자에 대한 철저한 아키텍처적 종속성(Lock-in) 없이, 심지어 와이파이가 완전히 끊긴 해저 터널이나 3만 피트 상공의 비행기 안에서도 최고 수준의 AI 앱 통합 테스트 스위트(Integration Test Suite) 파이프라인 전체를 눈부신 속도로 즉시 구동하고 빌드할 수 있게 해주는 압도적인 개발 엔진 환경의 독립 자율성을 제공한다.

3. 소결: 예측 불가의 파도를 멈추고 파이프라인의 수압을 테스트하라

결정론적이고 결함 없는 강건한 오라클을 CI/CD 상에 구축한다는 것은 무언가 대단한 AI 혁신이 아니다. 그것은 예측할 수 없고 제멋대로인 거대한 확률적 파도를 시시각각 일으키는 바깥세상의 LLM 블랙박스라는 폭주하는 심장을 잠시 인공적으로 얼려 멈춰(Mocking)두고, 오직 그 언어 모델 API를 둘러싸고 있는 우리 자체 애플리케이션의 배관망(Pipeline)과 예외 처리 밸브(Parser), 그리고 시스템 보호막 퓨즈 회로에 아주 미세한 메모리 누수 조각이나 결함이 없는지 기하학적이고 수학적인 치밀한 단위 정밀도로 혹독한 자체 논리망 수압 테스트를 진행하는 가장 위대하고도 결벽증적인 인프라 공학적 과정과 맞닿아 있다.