인프런 - 라이프타임 커리어 플랫폼
프로그래밍, 인공지능, 데이터, 마케팅, 디자인등 입문부터 실전까지 업계 최고 선배들에게 배울 수 있는 곳.
www.inflearn.com
인프런 사이트의 김영한님의 강의를 보면서 작성한 글입니다.
이전 포스팅에서는 순수 자바 코드만을 이용해 각 계층(Repository, Service)이 독립적으로 잘 동작하는지 확인하는 **단위 테스트(Unit Test)**를 진행했습니다.
하지만 실제 애플리케이션은 여러 계층이 서로 상호작용하며 동작합니다. 이번 포스팅에서는 스프링 컨테이너와 데이터베이스까지 모두 연동하여, 실제 애플리케이션 동작과 가장 유사한 환경에서 테스트하는 통합 테스트(Integration Test) 방법을 알아보겠습니다. ⚙️
## 1. 통합 테스트 환경 설정 (@SpringBootTest)
스프링 부트 환경에서 통합 테스트를 진행하기 위해서는 테스트 클래스 상단에 @SpringBootTest 어노테이션을 붙여주어야 합니다.
- @SpringBootTest: 이 어노테이션은 JUnit에게 "이 테스트는 스프링 부트와 함께 실행해야 해!"라고 알려주는 역할을 합니다. 테스트가 실행될 때, 실제 애플리케이션처럼 스프링 컨테이너를 생성하고 우리가 만든 모든 빈(Bean)들을 등록해 줍니다.
이제 스프링 컨테이너가 동작하므로, @Autowired를 사용하여 컨테이너에 등록된 실제 빈(Bean)을 테스트 클래스에 주입받을 수 있습니다.
@SpringBootTest
class MemberServiceIntegrationTest {
@Autowired MemberService memberService;
@Autowired MemberRepository memberRepository;
// ... 테스트 코드 ...
}
@BeforeEach가 필요 없는 이유: 이전 단위 테스트에서는 MemberService와 MemberRepository 객체를 직접 new로 생성하고 연결해주는 코드가 @BeforeEach에 있었습니다. 하지만 통합 테스트에서는 @Autowired를 통해 스프링 컨테이너가 이미 만들어 둔 진짜 빈들을 자동으로 주입해주므로, 해당 설정 코드가 더 이상 필요 없게 됩니다.
## 2. 테스트 데이터 자동 롤백 (@Transactional)
데이터베이스가 연결된 테스트의 가장 큰 고민은 "테스트 중에 DB에 저장된 데이터를 어떻게 처리할 것인가?" 입니다. 테스트가 끝날 때마다 DB에 저장된 데이터를 직접 지워주지 않으면, 다음 테스트에 영향을 주어 결과를 신뢰할 수 없게 됩니다.
@Transactional 어노테이션은 이 문제를 매우 깔끔하게 해결해 줍니다.
- @Transactional: 테스트 케이스에 이 어노테이션이 있으면, 각 테스트 메소드가 시작될 때 트랜잭션을 시작하고, 테스트가 끝나면 **결과와 상관없이(성공하든 실패하든) 항상 트랜잭션을 롤백(Rollback)**합니다.
즉, 테스트 중에 DB에 데이터를 아무리 많이 추가(INSERT)해도, 테스트가 끝나면 모든 것이 없던 일이 되어 원래의 깨끗한 상태로 돌아갑니다.
@AfterEach가 필요 없는 이유: 이전 단위 테스트에서는 @AfterEach를 사용하여 각 테스트가 끝난 후 메모리 저장소를 직접 비워주었습니다. 하지만 통합 테스트에서는 @Transactional이 자동으로 데이터베이스를 롤백해주므로, 수동으로 데이터를 지우는 코드가 더 이상 필요 없게 됩니다.
## 3. 통합 테스트 코드 예시
이제 두 어노테이션을 사용하여 실제 통합 테스트 코드를 작성해 보겠습니다.
@SpringBootTest
@Transactional // 이 어노테이션이 핵심!
class MemberServiceIntegrationTest {
@Autowired MemberService memberService;
@Autowired MemberRepository memberRepository;
@Test
void 회원가입() {
// given
Member member = new Member();
member.setName("spring_db_test");
// when
Long saveId = memberService.join(member);
// then
// @Transactional 덕분에 DB에 반영은 되지만, 최종 커밋은 되지 않음
Member findMember = memberRepository.findById(saveId).get();
assertThat(member.getName()).isEqualTo(findMember.getName());
}
@Test
public void 중복_회원_예외() {
// given
Member member1 = new Member();
member1.setName("spring");
Member member2 = new Member();
member2.setName("spring");
// when
memberService.join(member1);
// then
// DB에 이미 "spring"이라는 이름의 회원이 있으므로 예외가 발생해야 함
IllegalStateException e = assertThrows(IllegalStateException.class,
() -> memberService.join(member2));
assertThat(e.getMessage()).isEqualTo("이미 존재하는 회원입니다.");
}
}
이처럼 @SpringBootTest와 @Transactional을 함께 사용하면, 실제 운영 환경과 거의 동일한 조건에서 DB까지 연동하여 테스트하면서도, 테스트 데이터 관리를 매우 깔끔하게 자동화할 수 있습니다.
단위 테스트가 좋은 테스트일 확률이 더 높다고 합니다.
'개발 공부 > 백엔드' 카테고리의 다른 글
| 스프링 DB 접근 기술 : 3. JPA (0) | 2025.09.29 |
|---|---|
| 스프링 DB 접근 기술 : 2. JdbcTemplate (0) | 2025.09.27 |
| 스프링 DB 접근 기술 : 1. H2 데이터베이스 연동과 순수 Jdbc (0) | 2025.09.27 |
| 스프링 부트 - 스프링 MVC로 회원 관리 웹 기능 만들기 (0) | 2025.09.25 |
| 스프링 부트 - 스프링 빈과 의존관계 (0) | 2025.09.17 |