SPRING 입문 [ 코드로 배우는 스프링 부트 ]

[스프링 입문] 섹션 6.3 스프링 DB 접근 기술 (스프링 통합 테스트)

wlalsu_u 2023. 1. 17. 19:42

6.3.1  스프링 통합 테스트 코드 작성

 

 

앞서 섹션 3.5에서 진행한 회원 서비스 테스트의 경우,

 

스프링과는 관련 없이, 순수한 자바 코드만을 테스트하였다.

 

 

 

하지만 섹션 6.2에서 JDBC repository 로 DB까지 연결하는 코드를 테스트 하기 위해서는,

 

스프링 컨테이너와 DB를 연결한 통합 테스트를 진행해야 한다.

 

( Database Connection 정보들을 스프링 부트가 가지고 있기 때문)

 

 

 

 

먼저, test  >  java  >  hello.hellospring  >  service 폴더에

 

MemberServiceIntegrationTest 파일을 만들고 다음과 같이 코드 작성한다.

 

 

 

아래의 코드는 상단 일부만을 나타내었다.

 

 

 

@SpringBootTest
@Transactional 
class MemberServiceIntegrationTest {

    @Autowired MemberService memberService;
    @Autowired
    MemberRepository memberRepository;

 

 

@SpringBootTest

 

: 스프링 컨테이너와 테스트를 함께 실행하도록 하는 어노테이션

 

 

@Transactional

 

: test 를 진행하기 전에, transaction 을 한다.

 

: test 가 완료된 후, 롤백한다.

 

 

(아래 6.3.3에 추가 설명)

 

 

 

@Autowired

 

: test 에서는 injection 을 사용하지 않고, 단순히 Autowired 어노테이션을 주로 사용한다.

 

 

 

MemberRepository

 

: MemberServiceTest 에서는 MemoryMemberRepository 를 사용하였지만, MemberRepository 로 바꿔준다.

 

 

 

 

 

 

아래의 코드는 회원가입, 중복 회원 예약 test 코드이다.

 

MemberServiceTest 코드와 동일하게 작성한다.

 

 

 

@Test
    void 회원가입(){
        // given
        Member member = new Member();
        member.setName("spring");

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

        // then
        Member findMember = memberService.findOne(saveId).get();
        Assertions.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);
        assertThrows(IllegalStateException.class, () -> memberService.join(member2));

        // then

    }

 

 

 

전체 코드는 다음과 같다.

 

 

 

package hello.hellospring.service;


import hello.hellospring.domain.Member;
import hello.hellospring.repository.MemberRepository;
import hello.hellospring.repository.MemoryMemberRepository;
import org.assertj.core.api.Assertions;
import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.BeforeEach;
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.junit.jupiter.api.Assertions.assertThrows;

@SpringBootTest
@Transactional
class MemberServiceIntegrationTest {

    @Autowired MemberService memberService;
    @Autowired
    MemberRepository memberRepository;



    @Test
    void 회원가입(){
        // given
        Member member = new Member();
        member.setName("spring");

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

        // then
        Member findMember = memberService.findOne(saveId).get();
        Assertions.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);
        assertThrows(IllegalStateException.class, () -> memberService.join(member2));

        // then

    }

}

 

 

 

 


 

 

6.3.2  스프링 통합 테스트

 

 

코드 작성을 완료하고 회원가입 테스트 코드를 실행하면 오류가 발생한다.

 

 

이는 db 에 이미 'spring' 이라는 이름의 회원이 존재하는데,

 

회원 가입 테스트 코드에서 'spring' 이라는 동일한 이름의 회원을 저장하여 발생하는 오류이다.

 

 

(실제로 오류 메시지를 확인하면, '존재하는 회원' 이라는 문구를 확인할 수 있다.)

 

 

 

 

따라서, 먼저 DB 의 데이터를 모두 삭제 해야 한다.

 

H2 콘솔에서 아래와 같이 delete from member; 를 작성하여 데이터를 삭제한다.

 

 

 

 

 

 

+ 참고 )
실제 test 에서는 운영하고 있는 데이터를 삭제하는 것이 아니라, 테스트 전용 db를 따로 구축한다.

 

 

 

다시 회원가입 test 를 돌려보면, 

 

아래와 같이 정상적으로 작동하는 것을 볼 수 있다.

 

 

실제로 Spring 도 같이 뜨는 것도 확인할 수 있다.

 

 

 

 

 

 


 

6.3.3 @Transactoinal 추가 설명

 

 

 

앞서 6.3.2 에서 test 가 정상적으로 작동하고,

 

DB 에도 데이터가 정상적으로 들어가는 것을 확인할 수 있었다.

 

 

 

하지만, 회원가입 test 코드를 다시 한번 돌려보면, 오류가 발생하는 것을 확인할 수 있다. 

 

즉, test 를 반복할 수 없는 문제가 발생하게 된다. 

 

 

이를 위해 delete 메소드를 작성해도 되지만,

 

스프링에서는 Transactional 어노테이션을 지원한다.

 

 

 

@Transactional

 

 

data 는 커밋을 통해 DB에 반영이 되는데,

 

test 가 끝난 다음, 롤백 하도록 하여 DB 에 데이터가 반영되지 않도록 한다.

 

 

즉 별도의 코드를 작성하지 않아도, 테스트를 반복해서 수행할 수 있다.

 

 

 

Transactional 어노테이션을 사용하면,
DB 에 데이터가 반영되지 않으므로, 다음 test 에 영향을 주지 않는다.

 

 

+ 참고 )
@Transactional 은 test 에 사용했을 때만, 롤백하도록 동작한다.
(예를 들어 service 에 사용될 때에는 정상적으로 작동한다.)

 

 

 

 

실제로 test 를 여러번 반복해서 수행해도 오류가 발생하지 않는 것을 확인할 수 있다.

 

 

 

 

 

 

 

+ 참고 )
실제로는 앞서 실행한 통합 테스트보다,
순수한 자바 코드로 테스트 하는 '단위 테스트'를 하는 것이 더 바람직하다.

 

 

 

 

 

 

 

 

 

 

 

 

 

김영한 '스프링 입문 - 코드로 배우는 스프링 부트, 웹 MVC, DB 접근 기술' 강의를 기반으로 작성하였습니다.

https://www.inflearn.com/course/%EC%8A%A4%ED%94%84%EB%A7%81-%EC%9E%85%EB%AC%B8-%EC%8A%A4%ED%94%84%EB%A7%81%EB%B6%80%ED%8A%B8/dashboard