[Spring Boot] 테스트 데이터 불일치와 DI(의존성 주입)의 필요성

윤하빈·2026년 5월 3일

개발 공부

목록 보기
13/13

1. 문제 상황

MemberService 내부에서 Repository를 직접 new로 생성하면, 테스트 클래스에서 만든 Repository와 서비스 내부의 Repository는 이름만 같을 뿐 완전히 다른 메모리 주소를 가진 객체가 됨.

  • 현상: 테스트 코드에서는 memberRepository.clearStore()를 호출해 데이터를 비웠다고 생각하지만, 실제 서비스가 사용하는 내부 저장소는 비워지지 않고 데이터가 그대로 남아있었음.
  • 결과: 이전 테스트의 잔재가 다음 테스트에 영향을 주어, 실행 순서에 따라 성공과 실패가 갈리게 됨.

2. 원인 분석: 직접 생성의 한계

클래스 내부에서 private final MemberRepository = new ... 방식을 사용하면 외부에서 이 객체를 통제할 방법이 없음.

  • 강한 결합: 서비스가 저장소의 생성부터 생명주기까지 모두 관리함.
  • 테스트 불능: 테스트 환경에 맞는 '테스트 객체'를 끼워 넣을 수가 없음.

3. 해결책: 생성자를 통한 의존성 주입(DI)

서비스가 직접 객체를 만들지 않고, 생성자를 통해 외부에서 만들어진 객체를 받도록 구조를 변경해야 함.

// MemberService.java
public MemberService(MemberRepository memberRepository) {
    this.memberRepository = memberRepository; // 외부에서 넣어주는 걸 받기만 함
}

테스트 코드에서의 활용

@BeforeEach를 사용해 각 테스트가 시작되기 전, 동일한 Repository 인스턴스를 생성하여 서비스에 주입함.

@BeforeEach
public void beforeEach() {
    memberRepository = new MemoryMemberRepository(); // 저장소 생성
    memberService = new MemberService(memberRepository); // 같은 저장소를 서비스에 주입
}

이제 테스트 코드의 afterEach()가 비우는 저장소와 서비스가 사용하는 저장소가 완벽히 일치하게 됨.


4. 왜 DI가 '좋은 코드'의 기준인가?

의존성 주입을 적용하면 다음과 같은 이점이 있음.

  1. 테스트 용이성: 실제 DB 대신 메모리 DB를 자유롭게 갈아 끼울 수 있음.
  2. 결합도 낮추기: 서비스는 인터페이스에만 의존하고, 구체적으로 어떤 저장소가 들어올지는 외부에서 결정함.
  3. 데이터 정합성: 테스트와 운영 환경에서 객체의 상태를 일관되게 관리할 수 있음.

핵심 요약

  • 문제: 서비스 내부에서 객체를 직접 생성하면 테스트 환경과 격리됨.
  • 해결: 생성자 주입(DI)을 통해 외부에서 객체를 전달받음.
  • 결과: 테스트와 서비스가 동일한 인스턴스를 공유하여 테스트의 독립성이 보장됨.

0개의 댓글