1. Mock이란?
Mock은 테스트에서 진짜 객체 대신 쓰는 가짜 객체입니다.
주로 외부 의존성이 큰 코드(DB, 네트워크, 파일, 시간 지연 등)를 대체하여,
테스트를 빠르고, 안정적으로, 상황에 맞게 실행할 수 있게 해줍니다.
“Mock은 테스트의 세계에서 배우로 등장하는 대역 배우입니다.”
2. 왜 Mock을 쓰나?
- 빠른 테스트: DB 연결, API 호출, 대기 시간 없이 실행
- 상황 통제: 예외 발생, 특정 응답 값 등 원하는 상황 재현 가능
- 행동 검증: 어떤 함수가 몇 번, 어떤 인자로 호출됐는지 확인 가능
3. Python에서 Mock 도구
Python 표준 라이브러리 unittest.mock이 제공하는 주요 기능:
- Mock / MagicMock → 자유롭게 속성과 메서드를 정의할 수 있는 기본 가짜 객체
- patch → “사용되는 곳”의 객체를 일시적으로 Mock으로 교체
- return_value → 호출 시 반환할 값 지정
- side_effect → 호출 시 예외 발생, 호출별 다른 값 지정 등
- 검증 메서드 → assert_called_once(), assert_called_with(...), call_count 등
- spec / autospec → 실제 객체 인터페이스에 맞춰 Mock 생성
4. 간단 예제
from unittest.mock import Mock, patch
import time
# 1) 기본 Mock 사용
api = Mock()
api.fetch.return_value = {"ok": True}
print(api.fetch()) # {'ok': True}
api.fetch.assert_called_once()
# 2) patch 사용
@patch("time.sleep")
def test_retry(mock_sleep):
# sleep을 실제로 기다리지 않게 함
mock_sleep.return_value = None
# 여기서 retry 함수 호출...
mock_sleep.assert_called() # 호출 여부 확인
5. Django 테스트 예시
다음 예시는 Django 커맨드 wait_for_db가 DB 준비까지 대기하는 기능을 테스트하는 코드입니다.
from unittest.mock import patch
from psycopg2 import OperationalError as Psycopg2Error
from django.core.management import call_command
from django.db.utils import OperationalError
from django.test import SimpleTestCase
@patch('core.management.commands.wait_for_db.Command.check')
class CommandTest(SimpleTestCase):
def test_wait_for_db_ready(self, patched_check):
patched_check.return_value = True
call_command('wait_for_db')
patched_check.assert_called_once_with(database=['default'])
@patch('time.sleep')
def test_wait_for_db_delay(self, patched_sleep, patched_check):
patched_check.side_effect = [Psycopg2Error]*2 + [OperationalError]*3 + [True]
call_command('wait_for_db')
self.assertEqual(patched_check.call_count, 6)
여기서 Mock이 하는 일
- @patch('core.management.commands.wait_for_db.Command.check')
→ 실제 Command.check 메서드를 Mock으로 교체해 DB 점검을 흉내냅니다. - patched_check.return_value = True
→ DB가 바로 준비된 것처럼 시뮬레이션. - patched_check.side_effect = [...]
→ 처음 5번 호출은 예외 발생, 6번째에서 True 반환 → 재시도 로직 검증. - @patch('time.sleep')
→ 대기 시간을 실제로 기다리지 않도록 함.
6. Mock과 유사 개념
- Stub: 고정된 값만 반환하는 단순 대역
- Fake: 간단한 동작 구현을 가진 가짜(예: 메모리 DB)
- Spy: 실제 함수를 호출하면서 호출 정보를 기록(Mock의 변형)
7. 실전 팁
- “정의된 곳”이 아니라 “사용되는 곳” 경로로 patch하세요.
- autospec=True 옵션을 사용하면 실제 함수/메서드 시그니처를 강제해 오타 방지.
- 외부 시스템, 느린 연산, 불확정 동작(API 응답 랜덤 등)에 적극적으로 Mock 사용.
8. 마무리
Mock은 단순히 “가짜 객체”가 아니라, 테스트를 제어하고 검증하는 핵심 도구입니다.
잘 활용하면 테스트 속도를 크게 높이고, 예외 상황까지 안정적으로 커버할 수 있습니다.
💡 관련 문서
- Python 공식 문서: unittest.mock
- Django Testing: Testing in Django
'Programming > Django' 카테고리의 다른 글
| 🛠 Django Admin 설정 중 FieldError: username 오류 해결기 (TDD 기반 개발) (2) | 2025.08.06 |
|---|---|
| 🗄️ Django & SQL에서의 CASCADE와 NOT NULL 이해하기 (3) | 2025.08.05 |
| 🧪 테스트 주도 개발(TDD) 완벽 가이드 (4) | 2025.08.04 |
| 🐍 [Django 5.2 + S3 연동 에러 기록] STATICFILES_STORAGE가 무시되고 계속 로컬 staticfiles 디렉토리에만 저장될 때 (해결 완료!) (2) | 2025.08.01 |
| Django 프로젝트에 AWS S3 연동하기 (정적/미디어 파일 서빙 완전 정복) (3) | 2025.07.31 |