8.4 KiB
Mock Objects (가짜 객체)
📌 Brief Summary
Mock Objects(가짜 객체)는 단위 테스트(Unit Test)를 수행할 때 완벽한 격리(Isolation)를 달성하고 사이드 이펙트를 방지하기 위해 실제 협력 객체(Collaborator)를 대체하는 테스트 대역(Test Double)의 일종입니다 [1, 2]. 테스트를 위해 실제 시스템의 구성 요소처럼 보이게 만들고, 테스트 작성자가 미리 정의해 둔 응답(canned responses)을 반환하도록 설정됩니다 [2]. 리팩토링의 맥락에서는 특히 레거시 코드에서 복잡한 외부 자원(DB, 네트워크 등)의 의존성을 끊어내고 안전한 테스트 환경을 구축하는 데 핵심적인 역할을 수행합니다 [3, 4].
📖 기Core Content
-
테스트 격리와 부수 효과(Side Effect) 방지 단위 테스트 작성 시, 테스트 대상이 되는 코드가 데이터베이스 접근이나 네트워크 호출 등 느리거나 부수 효과가 큰 클래스를 호출할 때, 이를 Mock 객체나 Stub(스텁)으로 대체합니다 [1]. 이를 통해 복잡한 테스트 데이터 설정 없이 시스템을 완벽하게 격리(solitary)하여 테스트할 수 있습니다 [1, 2].
-
레거시 코드에서의 의존성 분리 도구 테스트가 없는 레거시 시스템을 리팩토링하기 위해서는 먼저 테스트를 작성하여 기존 동작을 기록해야 합니다 [4]. 마이클 페더스(Michael Feathers)는 코드를 직접 수정하지 않고도 프로그램의 동작을 바꿀 수 있는 '접점(Seam)'을 찾아, 외부 API 호출 등을 인터페이스로 추상화하고 테스트 시에 가짜 객체(Mock)를 주입하는 방식을 강조합니다 [3]. 이러한 방식으로 무거운 자원의 의존성을 제거하고 가벼운 대체물로 갈아 끼워 테스트라는 안전망을 확보한 뒤에 리팩토링을 수행해야 합니다 [4].
-
테스트의 구조화 및 예측 가능성 향상 Mock 객체는 실제 생산 코드에 사용될 객체를 가짜로 교체하여, 예상 가능한 반응을 미리 정의할 수 있게 해줍니다 [2]. 예를 들어, Mockito 같은 프레임워크를 이용하면 데이터베이스 저장소 대신 스텁을 사용하여 대상 메서드가 특정 파라미터를 받을 때 정의된 응답을 반환하도록 설정할 수 있으며, 이는 테스트를 단순하고 예측 가능하게 만듭니다 [5].
-
AI 기반 테스트 생성에서의 활용 최근 LLM(거대언어모델)을 통한 자동 테스트 생성 시에도 Mock 객체가 중요하게 다뤄집니다. 연구에 따르면 모델이 공통의 설정 로직, 표준화된 Mocking 패턴, 그리고 테스트 데이터와 로직의 분리를 적절히 활용하는 인프라를 자가 생성하기도 하며, 요청 가로채기에 기반한 API Mocking 계층을 구성하여 코드의 재사용성을 높인 사례가 있습니다 [6, 7].
⚖️ Trade-offs & Caveats
- 구현 세부 사항과의 과도한 결합 (Brittleness) 단위 테스트가 프로덕션 코드의 내부 구현에 너무 밀접하게 연관되면(예: 지나치게 많은 Mocking 사용), 코드를 리팩토링할 때마다 테스트가 깨지는 취약성이 발생할 수 있어 유지보수가 번거로워집니다 [8].
- Mock과 Stub의 용어 혼용 Mock과 Stub은 서로 다른 종류의 테스트 대역(Test Double)이지만, 개발자들 사이에서 종종 용어가 엄격히 구분되지 않고 혼용되어 사용되므로 주의가 필요합니다 [2].
- AI 테스트 생성 시의 한계 LLM을 활용해 자동화된 테스트를 작성할 때 모델이 충분한 Mocking 능력을 보이지 못하는(insufficient mocking capabilities) 문제점이 보고된 바 있습니다 [9]. 이를 방지하기 위해 내부 훅(internal hooks)에 대한 Mocking을 금지하는 등의 명시적인 프롬프트 및 규칙(rule file) 설정이 필요할 수 있습니다 [10].
🔗 Knowledge Connections
Related Concepts
[테스트 및 품질 관리 아키텍처]
-
- 연결 이유: Mock Objects와 Stub 모두 테스트 대역의 구체적인 구현 형태이기 때문입니다 [2].
- 이 개념을 통해 더 깊게 이해할 수 있는 부분: 실제 코드를 흉내 내어 테스트 환경을 구축하는 원리와 객체 간의 격리 메커니즘.
-
- 연결 이유: 레거시 코드 리팩토링 시, 코드를 직접 수정하지 않고 Mock 객체를 주입하여 동작을 변경할 수 있는 위치를 의미합니다 [3].
- 이 개념을 통해 더 깊게 이해할 수 있는 부분: 외부 의존성을 단절시키고 테스트 가능성을 높이는 소프트웨어 설계 기법 및 리팩토링의 준비 과정.
-
- 연결 이유: Mock Objects는 가장 작은 단위의 코드를 검증하는 단위 테스트의 의존성 제거를 위해 집중적으로 사용됩니다 [1, 11].
- 이 개념을 통해 더 깊게 이해할 수 있는 부분: 테스트 피라미드의 기초이자, 빠른 리팩토링 피드백 루프를 달성하기 위한 기본 환경.
[구현/활용 도구]
- Mockito
- 연결 이유: Java 환경에서 실제 클래스를 대체하여 깡통 응답(canned responses)을 정의하는 Stub/Mock을 생성할 때 널리 쓰이는 표준 프레임워크입니다 [5].
- 이 개념을 통해 더 깊게 이해할 수 있는 부분: 코드 상에서 Mock 객체를 실제로 설정하고, 'Arrange, Act, Assert' 패턴을 적용하는 구체적 구현 방식.
Deeper Research Questions
- Mock 객체와 Stub 객체의 구조적, 행동적 차이점은 정확히 무엇이며 각각 어떤 테스트 상황에서 선택하는 것이 가장 효율적인가?
- 레거시 코드 시스템에서 접점(Seam)을 찾아내고 기존 구조를 망가뜨리지 않으면서 Mock 객체를 안전하게 주입할 수 있는 리팩토링 패턴은 무엇인가?
- 내부 구현과 밀접하게 결합된 과도한 Mocking이 리팩토링 시 테스트를 깨지게 만드는 취약성(Brittleness)을 어떻게 최소화할 수 있는가?
- AI 코딩 에이전트에게 복잡한 의존성 구조의 코드를 주고 Mocking 기반의 단위 테스트 생성을 지시할 때, 할루시네이션을 막고 정확도를 높이기 위한 프롬프팅 전략은 무엇인가?
- 시스템의 모든 의존성을 Mocking하는 고립형(Solitary) 단위 테스트와 실제 객체를 사용하는 협력형(Sociable) 테스트 사이의 밸런스를 어떻게 조정해야 하는가?
Practical Application Contexts
- Implementation: Mockito와 같은 프레임워크를 도입하여 의존 객체를 스텁(stub)으로 변환하고, 특정 입력 시나리오에 대해 예상되는 결과값을 정의해 단위 테스트를 구현합니다 [5].
- System Design: 테스트 시점에 진짜 자원(DB 등) 대신 가짜 객체를 주입할 수 있도록, 외부 서비스나 데이터베이스 호출부를 인터페이스로 추상화하여 결합도를 낮추는 아키텍처를 설계합니다 [3, 4].
- Operation / Maintenance: 네트워크 연결이나 무거운 데이터베이스 로딩 없이 단위 테스트를 빠르게 실행할 수 있는 독립적 환경을 조성하여, 리팩토링이나 새로운 기능 추가 시 회귀 버그를 즉각 파악하는 지속적인 유지보수를 지원합니다 [1, 3, 12].
- Learning Path: TDD 및 단위 테스트의 기본 구조(Arrange, Act, Assert) 학습 → 테스트 대역(Test Doubles) 개념 이해 → 레거시 코드의 의존성 제거(Seam) 훈련 → 안전하고 과감한 리팩토링 수행 순서로 나아갑니다 [2, 3, 13].
- My Project Relevance: 방대하게 얽혀 있는 레거시 코드를 리팩토링하기 위해, 먼저 외부 API와 통신하는 부분의 의존성을 끊고 Mock 객체로 테스트 안전망을 구축하여 구조 개선의 위험을 최소화합니다 [3, 4].
Adjacent Topics
- Test-Driven Development (TDD)
- 확장 방향: 테스트를 먼저 작성한 후 코드를 구현하고 리팩토링(Red-Green-Refactor)하는 반복 개발 방식에 대한 이해 [14].
- Technical Debt (기술 부채)
- 확장 방향: 테스트 없이 작성되어 의존성이 엉켜있는 레거시 코드가 시스템의 유지보수성을 어떻게 떨어뜨리는지(엔트로피 증가), 이를 리팩토링으로 상환하는 개념에 대한 탐구 [15].
Last updated: 2026-05-03