이전의 테스트에서는 순수 java코드로만 구성되어져있는 테스트코드를 만들었었는데 이번에는 저번 시간에 연결한 db와 연동하여 테스트하기위해 Spring과 연결된 테스트코드를 만들어보는 시간이었다.
📂 test/java/service/MemberServiceIntegrationTest
package com.example.demo_practice.service;
import com.example.demo_practice.domain.Member;
import com.example.demo_practice.repository.MemberRepository;
import com.example.demo_practice.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.AssertionsForClassTypes.assertThat;
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("hello");
Member member2= new Member();
member2.setName("hello");
//when
Long saveId= memberService.join(member);
//then
Member findMember=memberService.findOneMember(saveId).get();
assertThat(member.getName()).isEqualTo(findMember.getName());
}
@Test
public void 중복_회원_예외(){
//given
Member member= new Member();
member.setName("hello");
Member member2= new Member();
member2.setName("hello");
//when
memberService.join(member);
IllegalStateException e = assertThrows(IllegalStateException.class, () -> memberService.join(member2));
assertThat(e.getMessage()).isEqualTo("이미 존재하는회원입니다.");
//then
}
}
코드를 확인하여보면 이전에 작성하였던 MemberServiceTest를 그대로 가져왔는데 여기서 차이가 나는 부분이 있다.
SpringBootTest를 선언하게 되면 순간적으로 이 테스트를 스프링 컨테이너와 함께 실행을 시키게된다. 그렇게 되면은 아까 처음에 말했던 우리가 연결한 h2데이터베이스와 다른 이전의 Bean으로 올렸던 것과 함께 바로 테스트를 수행할 수 있게 된다.
이전 테스트 코드들에서는 beforeEach, afterEach가 해당하는 코드들이 있었다. 각각의 이유가 있었지만 테스트가 진행이 되기전 MemoryMemberRepository과 service가 가리키는 저장소를 같게 하기 위해 DI를 하기 위한 이유가 있었다. 그러나 Transactional을 사용하게 되면 테스트 시작 전에 *트랜잭션을 시작하고, 테스트 완료 후에 항상 롤백을 하게 된다. 이렇게 하게 되면 이전 aftereach를 사용하던 clear과 같은 작업을 수행할 필요가 없어진다. 즉, DB에는 데이터가 남지 않게 된다는 얘기여서 다음 테스트에 영향을 주지 않는다는 뜻이다.
트랜잭션(Transaction)은 데이터베이스의 상태를 변환시키는 하나의 논리적 기능을 수행하기 위한 작업의 단위 또는 한꺼번에 모두 수행되어야 할 일련의 연산들을 의미한다.
여기서도 Autowired를 사용하였는데 이전과는 다르게 그냥 필드에서 Autowired를 선언하여 DI를 시켜주었다. 그치만 전에 말했듯이 필드에서 Autowired를 하게 되면 변경사항이 생길경우 변경할 수가 없어 기본적으로는 Constructor를 생성하여 DI를 한다고 하였다.
그치만 테스트환경과 같은 경우에서는 다음과 같은 테스트코드 안에서는 딱히 변경하지 않아도 DI만 시켜주는 역할만 하기 때문에 필드에서의 DI를 하였다.
김영한 - 스프링 입문 강의