본문 바로가기
Artificial Intelligence/60. Python

[PYTHON] Mock 객체 사용 시 spec=True 옵션이 중요한 이유 : 깨지지 않는 테스트를 위한 방어적 설계

by Papa Martino V 2026. 2. 20.
728x90

Mock 객체
Mock 객체

1. 서론: 편리하지만 위험한 유령, '기본 Mock'의 함정

파이썬의 unittest.mock 라이브러리는 가짜 객체를 만들어 복잡한 의존성을 분리하는 강력한 도구입니다. 하지만 기본 설정의 Mock은 치명적인 약점이 있습니다. 바로 '존재하지 않는 메서드나 속성에 접근해도 오류를 발생시키지 않는다'는 점입니다. 이는 실제 프로덕션 코드에서 메서드 이름이 변경되거나 삭제되었음에도 불구하고, 테스트 코드는 여전히 성공(Pass)으로 처리되는 '거짓 양성' 문제를 야기합니다. 오늘 우리는 이러한 '유령 호출'을 차단하고, 실제 클래스의 인터페이스를 엄격히 준수하게 만드는 spec(또는 autospec) 옵션의 가치와 활용법을 심층적으로 살펴봅니다.


2. spec 옵션 유무에 따른 동작 방식 비교

spec 옵션은 Mock 객체가 흉내 내야 할 대상(클래스나 인스턴스)의 청사진을 제공합니다. 이 옵션을 활성화하면 Mock은 대상에 정의되지 않은 속성에 접근할 때 즉시 AttributeError를 던집니다.

비교 항목 일반 Mock (MagicMock()) spec 적용 Mock (spec=TargetClass)
정의되지 않은 속성 접근 새로운 Mock 객체 생성 및 반환 AttributeError 발생 (차단)
메서드 오타 대응 오타가 나도 정상 실행된 것처럼 간주 즉시 테스트 실패로 오타 감지
인터페이스 정밀도 낮음 (무엇이든 수용함) 매우 높음 (대상 클래스 복제)
권장 사용 환경 매우 간단한 프로토타이핑 안정성이 중요한 모든 상용 테스트

3. Sample Example: 실전 코드로 보는 spec의 마법

아래는 이메일 발송 서비스를 테스트하는 시나리오입니다. 만약 개발자가 서비스 클래스의 메서드 이름을 send_email에서 deliver_email로 바꿨을 때, spec이 어떻게 우리를 구하는지 확인해 보세요.


from unittest.mock import MagicMock

class EmailService:
    def send_email(self, recipient, content):
        print(f"Sending to {recipient}...")

# 1. 일반 Mock 사용 시 (위험)
unsafe_mock = MagicMock()
# 실수로 메서드 이름을 sened_email(오타)로 호출해도 에러가 나지 않음!
unsafe_mock.sened_email("user@example.com", "Hello") 
print("Unsafe: 에러 없이 통과됨 (잠재적 버그)")

# 2. spec=True (또는 클래스 지정) 사용 시 (안전)
safe_mock = MagicMock(spec=EmailService)
try:
    # 존재하지 않는 메서드 호출 시 즉시 에러 발생
    safe_mock.sened_email("user@example.com", "Hello")
except AttributeError as e:
    print(f"Safe: 인터페이스 불일치 감지! -> {e}")

# 3. 인자(Arguments)까지 검증하고 싶다면 autospec=True
from unittest.mock import create_autospec
strict_mock = create_autospec(EmailService)
# 이제 존재 여부뿐만 아니라 인자 개수가 틀려도 에러를 발생시킵니다.

4. 전문적인 테스트 설계 제언

시니어 파이썬 개발자로서 강조하고 싶은 점은 "테스트는 실제 코드의 변화를 즉각 반영해야 한다"는 것입니다. spec=True를 사용하지 않는 Mock 테스트는 시간이 흐를수록 실제 코드와 괴리되어 가짜 안도감만 주는 '죽은 테스트'가 됩니다. 특히 대규모 리팩토링 단계에서 spec 옵션은 컴파일 언어의 타입 체크와 유사한 역할을 수행하여, 이름이 바뀐 메서드를 참조하는 모든 테스트 지점을 즉시 찾아내 줍니다.


5. 결론: 깨지지 않는 테스트를 위한 첫걸음

Mock 객체는 양날의 검입니다. spec 옵션을 통해 Mock에 '지성'을 부여하십시오. 실제 객체의 명세를 따르도록 강제하는 이 작은 옵션 하나가, 수백 개의 테스트 케이스가 실제 버그를 놓치지 않게 만드는 든든한 방어막이 될 것입니다.


참고 문헌 및 출처

  • Python Documentation: unittest.mock — Getting Started (specifying a spec)
  • Real Python: "Understanding the Python Mock Object Library"
  • Testing Python: Apply Clean Code Principles to Your Tests by David Sale
728x90