이 포스트는 김영한 이사님의 스프링 입문 강의를 듣고 작성하였습니다.
이번 시간에는 저번 시간에 작성했던 프로젝트에 이어서 Spring 통합 테스트를 진행해볼 예정이다. 자바 메모리상에서 동작하는 MemoryMemberRepository를 테스트 할 때와 달리 데이터베이스를 연결했을 때는 Spring 통합 테스트로 진행하여야 한다.
package memberpractice.memberpractice.service;
import memberpractice.memberpractice.domain.Member;
import memberpractice.memberpractice.repository.MemberRepository;
import memberpractice.memberpractice.repository.MemoryMemberRepository;
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.assertj.core.api.Assertions.*;
import static org.junit.jupiter.api.Assertions.*;
@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();
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);
// try{
// memberService.join(member2);
// fail();
// }catch (IllegalStateException e){
// assertThat(e.getMessage()).isEqualTo("이미 존재하는 회원입니다.");
// }
IllegalStateException e = assertThrows(IllegalStateException.class, () -> memberService.join(member2));
assertThat(e.getMessage()).isEqualTo("이미 존재하는 회원입니다.");
//then
}
}
다음과 같이 Test에 MemberServiceIntegrationTest를 새로 만들어서 구성을 하였다. 기존의 코드와 다른 것은 @SpringBootTest와 @Transactional이 클래스에 어노테이션으로 붙은 것을 확인할 수 있다.
또한, 필드를 보면 이제 테스트 클래스에서 객체를 직접 생성하는 것이 아닌 스프링 빈으로 등록한 객체들을 가져와 테스트를 진행 때문에 @AutoWired를 붙여서 의존성 주입을 받은 것을 확인할 수 있다.
이외에 기존의 테스트에서 존재하던 메모리를 지워주던 메소드인 clearStore는 더이상 사용하지 않는 것을 확인할 수 있다.
먼저 @Transactional어노테이션은 붙이지 않는 상태에서 회원가입만 테스트를 진행하여 보자.
기존에 우리가 진행했던 테스트와는 달리 실제 Spring이 실행되어 테스트가 진행된 것을 확인할 수 있다.
실제 우리의 로컬db에도 테스트 코드를 통해 넣은 값이 잘 들어가 있는 것을 확인할 수 있다.
중복 회원에 대한 예외도 정상적으로 잘 발생하는 것을 확인할 수 있다.
만약 동일한 테스트 코드로 회원가입 테스트를 한다면 어떻게 될까?
이미 DB상에 spring이라는 동일한 이름이 있기 때문에 당연히 예외를 던질 것이다.
여기서 사용할 수 있는 것이 우리가 주석처리한 @Transactional어노테이션이다.
@Transaction
이 어노테이션을 사용하면 테스트를 하나의
트랜잭션으로 묶고 테스트가 끝나면 다시 롤백을 해주기 때문에 우리가 일일이 지워주지 않아도 된다.트랜잭션에 대한 자세한 설명은 이 글을 참고하자.
즉 우리는 @Transaction을 통해 반복적인 테스트를 수행할 수 있게 된다.
@Transaction어노테이션을 붙여도 테스트가 정상적으로 진행된 것을 확인할 수 있다. 또한, 데이터를 지우는 별도의 작업을 하지 않아도 반복적인 테스트가 가능하게 된다.
이번 시간에는 간단하게 Spring 통합 테스트에 대해서 알아보았다. 어노테이션에 대해서 간략하게 살펴보면 다음과 같다.
@SpringBootTest: 스프링 컨테이너와 함꼐 테스트를 진행한다.
@Transactional: 테스트 시작전에 트랜잭션을 시작하고 테스트 완료후에 항상 롤백한다. 이렇게 되면 db에 데이터가 남지 않으므로 다음 테스트에 영향을 주지 않는다.
이렇게 배우고 나면 우리가 전에 했던 순수한 자바 코드를 활용한 테스트가 굳이 필요한가에 대한 의문이 생긴다. 하지만, 강의에서는 테스트를 짤 때 단위테스트가 통합테스트보다 더 좋은 테스트일 수 있다고 말하고 있다. 자세한 이유에 대해서는 이 글을 참고해보자.