본문 바로가기
Java/스프링 입문 - 스프링 부트, 웹 MVC, DB 접근 기술

[Spring Boot] Spring 통합 테스트(@SpringBootTest, @Transactional)

by Rezal 2022. 7. 5.

https://rezal.tistory.com/entry/%ED%9A%8C%EC%9B%90-%EA%B4%80%EB%A6%AC-%EC%98%88%EC%A0%9C-%EB%B0%B1%EC%97%94%EB%93%9C-%EA%B0%9C%EB%B0%9C-5-%ED%9A%8C%EC%9B%90-%EC%84%9C%EB%B9%84%EC%8A%A4-%ED%85%8C%EC%8A%A4%ED%8A%B8

 

[회원 관리 예제, 백엔드 개발 - (5)] 회원 서비스 테스트

git repository : https://github.com/Rezalog/spring-boot-entry-inf GitHub - Rezalog/spring-boot-entry-inf Contribute to Rezalog/spring-boot-entry-inf development by creating an account on GitHub. gi..

rezal.tistory.com

 

기존에 진행했던 MemberServiceTest 는 Spring 이 개입되지 않은 순수 자바 코드 테스트, 즉 단위 테스트라고 볼 수 있다.

단위테스트는 보통 로컬환경에서 개발자 개인별로 실행하는 경우가 많다.

 

이번에 진행해볼 테스트는 통합 테스트로, @SpringBootTest 및 @Transactional 로 Spring 위에서 테스트해보는 코드를 작성해보자.

(이번에도 편의상 제공하는 서비스 DB에 직접 CRUD 하고 확인하는데, 보통은 테스트용 DB가 따로 존재한다.)

 

 

MemberServiceIntegrationTest

package hello.hellospring.service;

import hello.hellospring.domain.Member;
import hello.hellospring.repository.MemberRepository;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.transaction.annotation.Transactional;

import static org.assertj.core.api.Assertions.assertThat;
import static org.junit.jupiter.api.Assertions.assertThrows;

@SpringBootTest
@Transactional
public class MemberServiceIntegrationTest {

    @Autowired MemberService memberService;
    // afterEach 로 DB clear 해주려면 Memory.. instance 필요
    @Autowired MemberRepository memberRepository;

    // 테스트는 빌드할때 포함 안되므로 메소드를 한글로 해도 무방하다.
    @Test
    void 회원가입() { // given, when, then 기법
        // given -- 주어진 상황에서(기반이 되는 데이터)
        Member member = new Member();
        member.setName("spring");

        // when -- 특정 경우에(검증해야하는 것)
        Long saveId = memberService.join(member);

        // then -- 이렇게 동작해야한다.(실제 검증)
        // member의 id 와 memberService의 saveId가 같은지
        Member findMember = memberRepository.findById(saveId).get();
        assertThat(member.getName()).isEqualTo(findMember.getName());
    }

    @Test // 예외도 잘 터지는지 봐야한다.
    void 중복_회원_예외() {
        Member member1 = new Member();
        Member member2 = new Member();

        member1.setName("spring");
        member2.setName("spring");

        memberService.join(member1);

        // 람다식 이용 : 에러상태 검증
        IllegalStateException e = assertThrows(IllegalStateException.class, () -> memberService.join(member2));

        // 에러 메세지 검증
        assertThat(e.getMessage()).isEqualTo("이미 존재하는 회원입니다.");

    }

}
  • @Autowired : 이 테스트용 클래스를 다른 곳에서 사용하거나 하지 않으므로, 편의상 필드형태로 DI 해준다.(현재 MemberRepository 의 구현 클래스는 JdbcMemberRepository)

  • @SpringBootTest : 이 어노테이션으로 스프링 컨테이너 환경에서 테스트가 가능하다.
  • **@Transactional : DB에서 데이터 관련 SQL 이 실행되면 반영되는 데이터의 흐름을 트랜잭션이라고 하는데, 이 트랜잭션이 commit 되어야 비로소 반영된다. 이때 @Transactional 어노테이션으로 다시 롤백시켜주므로 데이터를 테스트마다 delete 해줄 필요가 없다.

 

h2 console 에서 delete from member 쿼리로 데이터를 모두 지워준 뒤,

테스트를 실행하여 MemberServiceIntegrationTest 로그를 보면 Spring 위에서 테스트가 되는 것을 볼 수 있다.

Spring container 가 실행되기 때문에 이전보다 더 느리게 실행된다.