기존 기능 수정을 위한 단위 테스트와 통합 테스트 선택 기준과 실무 적용 가이드
기존 기능을 리팩토링할 때 회귀 버그를 방지하기 위해 단위 테스트와 통합 테스트 중 무엇을 먼저 작성해야 하는지 비교 기준과 상황별 선택 가이드를 제시합니다.
선택이 필요한 상황: 리팩토링 전 안전망 선택의 딜레마
레거시 코드를 개선하거나 함수 구조를 분리하는 리팩토링 작업을 시작할 때 개발자가 가장 먼저 맞닥뜨리는 두려움은 기존 동작이 깨지는 회귀 오류입니다. 코드를 수정하기 전에 테스트 코드를 먼저 작성해 안전망을 마련해야 한다는 점은 명확하지만, 구체적으로 개별 함수를 검증하는 단위 테스트를 작성해야 할지, 아니면 데이터베이스와 API 흐름까지 묶어서 확인하는 통합 테스트를 준비해야 할지 판단하기 어려운 상황이 자주 발생합니다.
특히 테스트 코드가 아예 없는 기존 프로젝트에서는 코드 내부가 강하게 결합되어 있어 단독 실행이 불가능한 경우가 많습니다. 이때 무작정 작은 단위부터 테스트를 만들려고 하면 모킹(Mocking) 설정에 지나치게 많은 시간이 소모되고, 반대로 통합 테스트만 작성하면 실행 속도가 느려져 빠른 피드백 루프를 얻기 어렵습니다. 따라서 현재 수정하려는 코드의 복잡도와 의존성 상태에 맞는 명확한 선택 기준이 필요합니다.

비교 기준: 실행 속도, 격리 수준, 리팩토링 내성
단위 테스트와 통합 테스트를 비교할 때 가장 중요한 세 가지 기준은 실행 속도, 외부 환경과의 격리 수준, 그리고 리팩토링 내성(Refactoring Tolerance)입니다. 단위 테스트는 외부 데이터베이스나 네트워크 I/O 없이 메모리 상에서 특정 함수나 클래스의 순수 로직만 검증하므로 실행 속도가 밀리초 단위로 매우 빠릅니다. 반면 통합 테스트는 실제 데이터베이스 쿼리나 서비스 컴포넌트 간의 상호작용을 함께 확인하기 때문에 실행 환경 구성이 복잡하고 전체 수행 시간이 상대적으로 길어집니다.
여기서 주목해야 할 실무 기준은 리팩토링 내성입니다. 내부 구현 세부사항(Private 메서드나 특정 내부 변수)과 강하게 결합된 단위 테스트는 코드 구조를 조금만 개선해도 테스트 자체가 깨지는 취약점이 있습니다. 반면 시스템의 입력과 최종 결과물 위주로 작성된 통합 테스트는 내부 구현 방식이 바뀌어도 외부 계약(Contract)이 유지된다면 깨지지 않고 기존 기능을 안정적으로 보호합니다. 따라서 검증하려는 대상이 순수 알고리즘인지, 컴포넌트 간의 연계 흐름인지에 따라 우선순위를 정해야 합니다.

상황별 차이: 순수 도메인 로직 vs 외부 의존성이 얽힌 레거시
복잡한 수식 계산, 할인 정책 적용, 문자열 파싱, 날짜 유효성 검증과 같이 입출력이 명확하고 외부 의존성이 없는 순수 비즈니스 로직을 리팩토링한다면 단위 테스트가 훨씬 효과적입니다. 다양한 경계값과 예외 케이스를 빠르게 추가하며 안심하고 함수 내부 코드를 정리할 수 있기 때문입니다. 순수 함수 형태의 도메인 로직은 단위 테스트 작성 비용이 낮고 실행 즉시 결과를 피드백받을 수 있어 작업 효율이 극대화됩니다.
반대로 컨트롤러에서 데이터베이스 트랜잭션을 호출하고 외부 결제 모듈까지 결합되어 있는 거대한 레거시 서비스 메서드를 리팩토링해야 한다면 통합 테스트를 먼저 확보해야 합니다. 내부 의존성을 억지로 떼어내어 단위 테스트를 만들려다가는 실제 동작과 다른 가짜 객체만 검증하게 되는 오류에 빠지기 쉽습니다. 이 경우에는 실제 DB 롤백 트랜잭션을 포함한 넓은 범위의 통합 테스트를 먼저 작성해 전체 동작을 보장한 뒤, 내부 코드를 작은 단위로 분리하면서 점진적으로 단위 테스트를 보강하는 전략이 적합합니다.

선택 예시: 결제 할인 로직 분리 시나리오
주문 처리 서비스 안에 500줄이 넘는 결제 할인 계산 로직이 포함되어 있는 프로젝트를 가정한 예시입니다. 이 상황에서 주문 서비스 전체를 단위 테스트로 작성하려면 데이터베이스 레포지토리, 알림 발송 객체, 사용자 세션 등을 모두 모킹해야 하므로 준비 작업이 매우 방대해집니다. 이때 권장되는 실무 절차는 먼저 주문 API 엔드포인트에 대한 통합 테스트를 1~2개 작성하여 실제 결제 금액이 올바르게 차감되는지 확인하는 기본 안전망을 만드는 것입니다.
그 다음 단계로 거대한 메서드 안에서 복잡한 조건문으로 얽혀 있는 할인 계산 수식만을 별도의 순수 도메인 클래스로 추출합니다. 새롭게 분리된 순수 할인 계산기 클래스는 외부 의존성이 없으므로, 쿠폰 중복 적용이나 회원 등급별 할인 등 다양한 경계값 케이스를 검증하는 촘촘한 단위 테스트를 작성합니다. 이처럼 진입점에는 안정적인 통합 테스트를 두고, 핵심 로직 추출 후에는 빠른 단위 테스트를 덧붙이는 하이브리드 접근이 안전한 리팩토링의 정석입니다.

결정 체크리스트: 테스트 전략 선택 전 필수 확인 사항
리팩토링 착수 전 어떤 테스트를 우선 작성할지 결정할 때는 다음 점검 항목을 순서대로 확인하시기 바랍니다. 첫째, 수정하려는 코드가 데이터베이스 쿼리나 네트워크 통신에 직접 의존하고 있는지 점검합니다. 의존성이 높다면 억지 모킹을 피하고 통합 테스트를 우선 작성합니다. 둘째, 이번 리팩토링 목표가 내부 구조 개선인지, 퍼블릭 인터페이스 스펙 변경인지 확인합니다. 외부 스펙을 유지하는 내부 개선이라면 넓은 범위의 블랙박스 테스트가 안전합니다.
셋째, 전체 테스트 스위트의 실행 환경과 CI 파이프라인 수행 시간을 고려합니다. 이미 통합 테스트 실행 시간이 수 분 이상 지연되고 있다면 순수 로직을 최대한 분리하여 단위 테스트 비중을 늘려야 합니다. 마지막으로 경계값 처리가 중요한 핵심 알고리즘인지 확인하여, 입력 조건이 다양한 분기 로직은 반드시 독립된 단위 테스트로 격리하여 100%에 가까운 분기 커버리지를 확보해야 합니다.