Intro
이전에 JdbcTemplate를 이용해 데이터를 메모리가 아닌 DB에 접근하도록 변경했다.
그렇기 때문에 기존의 테스트는 스프링과 상관없이 순수 Java 코드를 이용한 테스트였는데,
이제부터는 DB 서버 URL, 설정 등을 스프링이 갖고 있기 때문에 서버를 올려 테스트를 진행해야 한다.
테스트 케이스 작성
우선 서비스의 기능은 같기 때문에 이전에 만들었던 MemberServiceTest를 복사해서 가져오자.
MemberServiceIntegrationTest.java
package com.devjaewoo.hellospring.service;
import com.devjaewoo.hellospring.domain.Member;
import com.devjaewoo.hellospring.repository.MemoryMemberRepository;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import java.util.List;
import static org.assertj.core.api.Assertions.*;
import static org.junit.jupiter.api.Assertions.*;
class MemberServiceIntegrationTest {
MemoryMemberRepository memberRepository;
MemberService memberService;
@BeforeEach
public void setUp() {
memberRepository = new MemoryMemberRepository();
memberRepository.clearStore();
memberService = new MemberService(memberRepository);
}
@Test
void join() {
//given
Member member = new Member();
member.setName("spring");
//when
Long saveId = memberService.join(member);
//then
Member result = memberService.findOne(saveId).orElse(null);
assertThat(result.getName()).isEqualTo(member.getName());
}
@Test
public void join_duplicated_exception() {
//given
Member member1 = new Member();
member1.setName("spring");
Member member2 = new Member();
member2.setName("spring");
//when
memberService.join(member1);
//then
IllegalStateException e = assertThrows(IllegalStateException.class, () -> memberService.join(member2));
assertThat(e.getMessage()).isEqualTo("이미 존재하는 회원입니다.");
}
@Test
void findMembers() {
//given
Member member1 = new Member();
member1.setName("spring1");
Member member2 = new Member();
member2.setName("spring2");
//when
memberService.join(member1);
memberService.join(member2);
//then
List<Member> result = memberService.findMembers();
assertThat(result.size()).isEqualTo(2);
}
@Test
void findOne() {
//given
Member member1 = new Member();
member1.setName("spring1");
Member member2 = new Member();
member2.setName("spring2");
//when
Long id1 = memberService.join(member1);
Long id2 = memberService.join(member2);
//then
Member result1 = memberService.findOne(id1).orElse(null);
Member result2 = memberService.findOne(id2).orElse(null);
assertThat(result1.getName()).isEqualTo(member1.getName());
assertThat(result2.getName()).isEqualTo(member2.getName());
}
}
이제 테스트 클래스에 아래의 어노테이션을 추가해줘야 한다.
- @SpringBootTest
- @Transactional
@SpringBootTest
@Transactional
public class MemberServiceIntegrationTest {
...
}
@SpringBootTest 어노테이션을 추가하면 테스트 시작 시 자동으로 스프링을 시작해준다.
@Transactional 어노테이션을 테스트 클래스에 추가하면 각 테스트가 끝날 때
자동으로 DB를 테스트 시작 전으로 Rollback 시켜준다.
그렇기 때문에 데이터를 비워주기 위해 사용했던 @BeforeEach와 setUp 함수가 더 이상 필요 없어졌다. 지워주자.
대신 memberRepository와 memberService 변수를 초기화시켜줘야 하는데,
지금 테스트는 스프링 환경에서 동작하므로 @Autowired를 붙여주면 자동으로 의존성 주입이 된다.
@Autowired MemberRepository memberRepository;
@Autowired MemberService memberService;
변수에 직접 @Autowired를 붙이는 건 좋은 방법이 아니지만,
테스트 코드는 실제 서버에 영향을 주지 않기 때문에 편한 방식으로 하는 것도 괜찮다.
최종 코드는 다음과 같다.
MemberServiceIntegrationTest.java
package com.devjaewoo.hellospring.service;
import com.devjaewoo.hellospring.domain.Member;
import com.devjaewoo.hellospring.repository.MemberRepository;
import com.devjaewoo.hellospring.repository.MemoryMemberRepository;
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 java.util.List;
import static org.assertj.core.api.Assertions.*;
import static org.junit.jupiter.api.Assertions.assertThrows;
@SpringBootTest
@Transactional
public class MemberServiceIntegrationTest {
@Autowired MemberRepository memberRepository;
@Autowired MemberService memberService;
@Test
void join() {
//given
Member member = new Member();
member.setName("spring");
//when
Long saveId = memberService.join(member);
//then
Member result = memberService.findOne(saveId).orElse(null);
assertThat(result.getName()).isEqualTo(member.getName());
}
@Test
public void join_duplicated_exception() {
//given
Member member1 = new Member();
member1.setName("spring");
Member member2 = new Member();
member2.setName("spring");
//when
memberService.join(member1);
//then
IllegalStateException e = assertThrows(IllegalStateException.class, () -> memberService.join(member2));
assertThat(e.getMessage()).isEqualTo("이미 존재하는 회원입니다.");
}
@Test
void findMembers() {
//given
Member member1 = new Member();
member1.setName("spring1");
Member member2 = new Member();
member2.setName("spring2");
//when
memberService.join(member1);
memberService.join(member2);
//then
List<Member> result = memberService.findMembers();
assertThat(result.size()).isEqualTo(2);
}
@Test
void findOne() {
//given
Member member1 = new Member();
member1.setName("spring1");
Member member2 = new Member();
member2.setName("spring2");
//when
Long id1 = memberService.join(member1);
Long id2 = memberService.join(member2);
//then
Member result1 = memberService.findOne(id1).orElse(null);
Member result2 = memberService.findOne(id2).orElse(null);
assertThat(result1.getName()).isEqualTo(member1.getName());
assertThat(result2.getName()).isEqualTo(member2.getName());
}
}
이제 코드를 작성했으니 테스트를 돌려보자.
아마 실습을 열심히 했다면 아래의 사진처럼 테스트 대부분이 실패할 것이다.
우리가 이전에 입력한 데이터가 DB에 그대로 남아있어서 발생하는 오류로, 실습하면서 추가한 데이터가 테스트에 영향을 줘서 실패가 뜨는 것이다.
남아있는 데이터를 지워야 하는데, h2 콘솔로 다시 들어가서 아래의 SQL을 입력해 실습하며 추가한 데이터를 지워주자.
DELETE FROM MEMBER;
또는
DROP TABLE IF EXISTS MEMBER;
CREATE TABLE MEMBER (
ID BIGINT GENERATED BY DEFAULT AS IDENTITY,
NAME VARCHAR(255),
PRIMARY KEY(ID)
);
실제 개발 시에는 테스트할 때마다 데이터를 날리면 안 되고 테스트용 DB를 따로 분리해야 한다.
테스트 결과
이제 다시 테스트를 진행해보자.
테스트가 모두 통과된 것을 볼 수 있다.
이쯤에서 "모든 단위 테스트를 통합 테스트로도 할 수 있는 거 아닌가?" 하는 생각이 들 수 있는데,
단위 테스트는 Java 코드만 실행하는 반면에 통합 테스트는 스프링 서버를 실행하고 테스트를 수행하기 때문에 속도 측면에서 어마어마하게 차이가 난다.
테스트를 한두 개 정도만 돌릴 때는 별 차이를 느끼지 못하겠지만,
테스트가 쌓이면 쌓일수록 시간 차이가 많이 나게 될 것이다.
때문에 가능한 한 테스트는 단위 테스트로 작성하는 것이 좋다.
다음 시간에는 JPA를 사용해서 DB에 접근해보자.
출처
'Study > Spring Boot' 카테고리의 다른 글
[Spring Boot] Spring Data JPA 써보기 (0) | 2022.02.15 |
---|---|
[Spring Boot] JPA로 JdbcTemplate 대체하기 (0) | 2022.02.15 |
[Spring Boot] JdbcTemplate로 MemoryRepository 대체하기 (0) | 2022.02.14 |
[Spring Boot] h2 Database 설정하기 (0) | 2022.02.14 |
[Spring Boot] h2 DB에 TCP 접근 시 SocketTimeoutException 뜰 때 (0) | 2022.02.14 |