Mock을 너무 많이 사용하면 테스트는 통과하지만 실제 운영 환경에서는 에러가 발생하는 '가짜 안도감'에 빠지게 됩니다. 이는 테스트 코드가 실제 객체의 동작이 아니라 개발자가 임의로 설정한 가짜 동작만을 검증하기 때문입니다.
테스트 더블의 일종인 Mock은 외부 의존성을 분리하여 테스트 속도를 높이고 격리된 환경을 제공하는 유용한 도구입니다. 하지만 프로젝트 규모가 커질수록 모든 의존성을 Mock으로 대체하려는 유혹에 빠지기 쉬우며, 이는 곧 유지보수의 재앙으로 이어지곤 합니다.
개발자가 내부 로직을 리팩토링할 때마다 기능은 정상인데 테스트 코드만 줄줄이 깨지는 경험을 하고 있다면, 그것은 Mock을 과도하게 사용하고 있다는 강력한 신호입니다. 테스트가 구현 세부 사항에 너무 깊게 결합되어 있다는 뜻이기 때문입니다.
이 글에서는 Mock 과다 사용이 초래하는 구체적인 문제점과 함께, 어떤 상황에서 Mock을 지양해야 하는지, 그리고 더 나은 테스트 설계를 위한 실무적인 판단 기준은 무엇인지 정리해 보겠습니다.
핵심 내용 먼저 보기
핵심 키워드 mock 과다 사용 · 연관 검색어 mock 과다 사용, 단위 테스트 설계, 테스트 더블, 리팩토링 내성, 소프트웨어 테스트 전략
구현 세부 사항에 결합되어 리팩토링을 방해하는 테스트
Mock을 남발할 때 발생하는 가장 큰 문제는 테스트 코드가 '무엇을(What)' 검증하는지가 아니라 '어떻게(How)' 동작하는지를 감시하게 된다는 점입니다. 예를 들어, 특정 서비스가 내부적으로 어떤 메서드를 몇 번 호출했는지, 인자값은 무엇이었는지를 일일이 Mock으로 검증(Verification)하는 방식이 대표적입니다.
이런 방식은 코드의 내부 구조를 조금만 개선해도 테스트가 실패하게 만듭니다. 결과적으로 개발자는 로직을 개선하는 시간보다 깨진 테스트 코드를 수정하는 데 더 많은 시간을 쓰게 되며, 이는 테스트가 개발을 돕는 것이 아니라 오히려 발목을 잡는 결과를 초래합니다. 진정한 의미의 리팩토링 내성을 갖추려면 Mocking보다는 최종 결과값이나 상태 변화를 검증하는 데 집중해야 합니다.
실제 객체의 변경사항을 반영하지 못하는 가짜 동작
Mock은 개발자가 정의한 대로만 움직입니다. 만약 실제 객체의 인터페이스나 반환 타입이 변경되었음에도 Mock 설정(Stubbing)을 업데이트하지 않는다면, 테스트는 여전히 성공하지만 실제 애플리케이션은 런타임 에러를 뱉어낼 것입니다. 이것이 Mock 과다 사용이 만드는 '거짓 양성'의 위험성입니다.
특히 복잡한 비즈니스 로직을 가진 내부 클래스들을 모두 Mock으로 치환하면, 객체 간의 협력 관계에서 발생하는 미묘한 버그들을 잡아낼 기회를 완전히 놓치게 됩니다. 테스트가 실제 코드의 동작을 보장하지 못한다면 그 테스트는 존재 가치를 잃은 것이나 다름없습니다.
Mock 대신 Fake 객체와 통합 테스트 활용하기
모든 것을 Mock으로 만들지 말고, 실제 객체를 사용하거나 'Fake' 객체를 도입하는 것을 고려해 보세요. 예를 들어, 실제 데이터베이스를 사용하는 대신 메모리 내 데이터베이스(In-memory DB)를 사용하거나, 복잡한 외부 API 대신 미리 준비된 응답을 주는 가짜 서버를 띄우는 방식입니다.
Fake 객체는 Mock과 달리 실제 로직의 단순화된 버전을 포함하고 있어, 호출 횟수를 검증하는 대신 실제 데이터의 흐름을 확인할 수 있게 해줍니다. 또한, 핵심 비즈니스 흐름에 대해서는 단위 테스트에만 집착하지 말고 여러 객체가 실제로 맞물려 돌아가는 통합 테스트 비중을 적절히 섞어주는 것이 훨씬 견고한 시스템을 만드는 길입니다.
실무에서 Mock 사용 여부를 결정하는 판단 기준
Mock을 써야 할지 말지 고민된다면 다음의 기준을 적용해 보시기 바랍니다. 첫째, 제어할 수 없는 외부 요인(서드파티 API, 이메일 발송, 현재 시간 등)인가? 둘째, 실제 객체를 생성하는 비용이 너무 커서 테스트 실행 속도를 현저히 떨어뜨리는가? 이 두 경우에 해당하지 않는다면 가급적 실제 객체를 사용하는 것이 좋습니다.
만약 테스트 코드에서 Mock을 설정하는 코드(Setup)가 실제 검증 로직보다 길어지고 있다면, 이는 설계 자체가 잘못되었다는 신호일 수 있습니다. 클래스가 너무 많은 의존성을 가지고 있거나 책임이 비대해진 것은 아닌지 먼저 점검해 보세요. Mock을 줄이려는 노력이 자연스럽게 더 나은 객체지향 설계로 이어지는 경우가 많습니다.
테스트의 본질은 코드 변경에 대한 자신감을 얻는 것입니다. 하지만 Mock에 의존한 테스트는 코드 구조가 바뀔 때마다 무너지며 그 자신감을 갉아먹습니다. 도구의 편리함에 매몰되지 않고, 실제 객체들이 어떻게 협력하는지를 검증하는 데 더 많은 관심을 기울여야 합니다.
물론 모든 Mock을 없애는 것은 불가능하며 효율적이지도 않습니다. 중요한 것은 Mock을 '격리'를 위한 최후의 수단으로 남겨두고, 가능한 한 실제 도메인 모델과 로직이 살아있는 테스트를 작성하는 습관을 들이는 것입니다. 테스트 코드가 실제 구현의 거울이 될 때 비로소 안정적인 배포가 가능해집니다.
이후에는 효율적인 테스트 환경 구축을 위한 '테스트 피라미드 전략'이나 '의존성 주입을 통해 테스트하기 좋은 코드 만들기'와 같은 주제를 통해 더 깊이 있는 설계 고민을 이어가 보시기 바랍니다.
자주 묻는 질문
Mock을 쓰면 테스트 속도가 빨라지는데 왜 지양해야 하나요?
속도는 빠르지만 테스트의 정확도가 떨어지기 때문입니다. 실제 객체의 동작을 반영하지 못하는 Mock은 버그를 놓칠 위험을 높이고, 내부 구현에 종속된 테스트를 만들어 리팩토링을 어렵게 합니다.
리팩토링할 때 테스트가 깨지는 건 당연한 것 아닌가요?
외부로 드러나는 기능(Behavior)이 변하지 않았다면 테스트는 깨지지 않아야 합니다. 테스트가 깨진다면 그것은 로직이 아니라 '구현 방식'을 검증하고 있었다는 증거이며, 이는 Mock을 과하게 사용했을 때 흔히 나타나는 증상입니다.
그럼 Mock은 언제 사용하는 것이 가장 좋나요?
데이터베이스, 외부 API 호출, 파일 시스템 접근, 혹은 실행 시마다 결과가 달라지는 난수나 시간 정보처럼 테스트 환경에서 제어하기 힘든 외부 의존성에 한해 사용하는 것이 가장 이상적입니다.
해시태그
#mock과다사용 #단위테스트설계 #테스트더블 #리팩토링내성 #소프트웨어테스트전략 #TDD부작용
'IT' 카테고리의 다른 글
| 문서 분류 AI 구축 시 실패하지 않는 모델 선택과 데이터 라벨링 기준 (0) | 2026.07.20 |
|---|---|
| 고객센터 AI 도입, 단순 챗봇을 넘어 실질적인 운영 효율을 높이는 업무 선정과 구축 전략 (0) | 2026.07.20 |
| AI 도입 체크리스트: 기술보다 먼저 점검해야 할 실무 운영 가이드 (0) | 2026.07.20 |
| 기업 실적 발표 속 AI 키워드, 단순한 유행어인지 실질적 성장 동력인지 구분하는 법 (0) | 2026.07.20 |
| 구글 서치콘솔 색인 안됨 원인 파악과 해결을 위한 단계별 가이드 (0) | 2026.07.20 |