[스프링 입문] Section07. 스프링 DB 접근 기술[3] - 스프링 통합 테스트

Euiyeon Park·2025년 6월 17일

갓영한 스프링🍀

목록 보기
7/12
post-thumbnail

스프링 통합 테스트

  • 스프링 컨테이너와 DB까지 연결한 통합 테스트
  • @SpringBootTest : 스프링 컨테이너와 테스트를 함께 실행
  • @Transactional : 테스트 시작 전에 트랜잭션을 시작, 테스트 완료 후 롤백

스프링을 띄우는 테스트가 왜 필요할까?

  1. 빈(Bean) 관리 검증
  • 빈이 올바르게 생성되고 의존성이 주입되는지 검증
    • Ex. MemberServiceMemberRepository에 의존하는지 확인.
  1. 트랜잭션 테스트
  • 실제 데이터베이스와 연결하여 쿼리 실행 후 롤백되는지 검증
    • Ex. INSERT 이후 데이터가 저장되었는지 확인하고 테스트 후 원상복구
  1. 통합 테스트
  • 컨트롤러, 서비스, 리포지터리 등 애플리케이션의 여러 계층이
    올바르게 상호작용하는지 테스트
    • Ex. HTTP 요청 → 컨트롤러 → 서비스 → 레포지터리 흐름 검증
  1. Mock 환경 테스트
  • 웹 요청을 테스트하거나, 모의 객체(Mock)를 활용하여 특정 부분만 검증
    • Ex. MockMvc를 이용한 HTTP 요청 시나리오 검증

📂 MemberServiceIntegrationTest

@SpringBootTest
@Transactional
class MemberServiceIntegrationTest {
    @Autowired MemberService memberService;

    // 📌 구현체는 @Configuration한 곳에서 주입받음
    @Autowired MemberRepository memberRepository;

    // 📌 직접 객체 생성 방식❌ -> 스프링 컨테이너에게 주입받는 방식으로 변경
//    @BeforeEach
//    void beforeEach(){
//        memberRepository = new MemoryMemberRepository();
//        memberService = new MemberService(memberRepository);
//    }

    // 📌 테스트의 반복 가능 -> @Transactional로 해결
//    @AfterEach
//    void afterEach(){
//        memberRepository.clearStore();
//    }

    @Test
    // @Commit     // 테스트 데이터가 롤백되지않고 DB에 반영
    void 회원가입() {
        // given
        Member member = new Member();
        member.setName("zizon의연v");

        // when
        Long savedId = memberService.join(member);

        // then
        // Service의 findMember()로 테스트
        Member findMember1 = memberService.findMember(savedId).get();
        assertThat(member.getName()).isEqualTo(findMember1.getName());

        // Repository의 findById()로 테스트
        Member findMember2 =  memberRepository.findById(savedId).get();

    }

    @Test
    void 중복_회원_예외(){
        // given
        Member member1 = new Member();
        member1.setName("zizon의연v");

        Member member2 = new Member();
        member2.setName("zizon의연v");

        // when
        memberService.join(member1);
		
        // then
        IllegalStateException e = assertThrows(IllegalStateException.class, 
				        () -> memberService.join(member2));
        assertThat(e.getMessage()).isEqualTo("이미 존재하는 회원입니다.");
    }
    
    ...
    
}

🍀통합 테스트에서 @Transactional을 사용하는 이유

스프링 부트 통합 테스트(@SpringBootTest)에서 @Transactional을 붙이면,

  • 테스트 메서드가 끝난 뒤 자동으로 트랜잭션 롤백
  • 테스트로 인해 DB에 변경된 내용이 테스트 종료 후 남지 않도록

@Transactional 동작 원리

  • 테스트가 실행되면 @Transactional
  • 트랜잭션을 시작하고
  • 테스트가 끝나면 rollback()이 실행

@Transactional가 통합 테스트에서 중요한 이유

  1. 테스트를 실행할 때마다 DB가 초기 상태로 보장 - 반복 실행 가능
  2. 데이터가 섞이지 않아 테스트 간 간섭이 없음 - 테스트 격리
  3. 실제 DB 환경에서 서비스/레포지토리 계층을 통합적으로 검증 가능
profile
"개발자는 해결사이자 발견자이다✨" - Michael C. Feathers

0개의 댓글