Mock, Patch를 이용해 외부 API 의존성 테스트하기
외부 API에 의존하는 코드를 테스트할 때 발생하는 속도, 비용, 비결정성 문제를 Mock과 patch를 활용해 해결하는 방법
Mock과 patch의 필요성
외부 API 의존 코드 테스트 시 문제점:
속도: 네트워크 호출로 인한 테스트 속도 저하
비용: API 호출 횟수에 따른 비용 발생
비결정성: 외부 서버 상태에 따른 테스트 결과 변동
제약: 특정 상황(결제 실패, 인증 실패) 재현의 어려움
Mock과 patch 기본 개념
Mock: 실제 객체를 흉내 내는 가짜 객체로 반환 값과 예외를 설정 가능
patch: 특정 모듈/클래스/함수를 테스트 중 Mock 객체로 대체
patch 사용법
데코레이터 방식
@patch('weather.services.WeatherService.get_weather_for_city')
def test_get_weather_success(self, mock_get_weather):
mock_get_weather.return_value = {"temperature": 25}
response = self.client.get("/api/weather?city=Seoul")
mock_get_weather.assert_called_once_with("Seoul")컨텍스트 매니저 방식
def test_get_weather_success(self):
with patch('weather.services.WeatherService.get_weather_for_city') as mock_get_weather:
mock_get_weather.return_value = {"temperature": 25}
response = self.client.get("/api/weather?city=Seoul")핵심 원칙과 팁
patch 경로 설정 원칙
"정의된 곳이 아니라 사용되는 곳을 patch"
틀린 방법:
@patch('requests.get')올바른 방법:
@patch('weather.services.requests.get')
autospec=True 활용
@patch('weather.services.WeatherService.get_weather_for_city', autospec=True)원본 객체의 시그니처를 복제하여 더 안전한 Mock 생성
side_effect 활용
예외 발생과 동적 반환 값 제어:
# 예외 발생
mock_get_weather.side_effect = requests.RequestException("Connection failed")
# 호출마다 다른 값 반환
mock_api_call.side_effect = [{"id": 1}, {"id": 2}, ValueError("Limit reached")]Mock 호출 검증
테스트 마지막에 Mock이 예상대로 호출되었는지 반드시 검증:
mock_get_weather.assert_called_once_with("Seoul")Last updated
