Spring Boot_ 스프링 통합 테스트

이세미·2023년 5월 18일
0

SpringBoot

목록 보기
18/23
post-thumbnail

스프링 컨테이너와 DB까지 연결한 통합 테스트

이전에 했던 test들은, 전혀 스프링과 관련이 없는 테스트들 이었다.

순수한 java 코드를 가지고 테스트 한 것이었는데,
데이터베이스 connection 정보도 스프링부트가 가지고 있으니
이젠 java 코드를 가지고 테스트 할 수 없다.

테스트를 스프링과 엮어서 해볼 것이다.

MemberServiceTest와 똑같은 버전인데,
db까지 연결해서 실행하는 test를 만들어 보겠다.

test - service에 MemberServiceTest를 복사붙여넣기 한 클래스, MemberServiceIntegrationTest를 만들었다.

그리고 @SpringBootTest, @Trasactional 을 추가하였다.

MemberServiceTest에서는 직접 @BeforeEach로 memberService와 memberRepository를 객체 생성해서 넣었었는데,

이제는 스프링 컨테이너한테 요청을 해야하기 때문에
@BeforeEach 코드를 삭제하였다.

Test는 최대한 제일 편한 방법을 쓰기 때문에
MemberService memberService;
MemoryMemberRepository memberRepository; 의 앞에
@Autowired를 넣어주면 편하다.

그리고 MemoryMemberRepository memberRepository;는

MemberRepository memberRepository;로 바꿔준다.

@AfterEach는 메모리 db에 있는 data를
다음 test의 영향 없게 지워주는 코드였으므로
필요 없으니 지워주면, 위와 같은 코드가 된다.

또 맨 밑에 있었던

@Test
void findMembers() {
}
@Test
void findOne() {
}

도 지워주었다.

이 상태로 회원가입 코드만 실행시켜 보았더니,

‘이미 존재하는 회원입니다’ 라는 에러가 뜬다.

이유가 무엇일까?

바로 이전에 실습했었던 db에 spring이라는 이름을 가진 data가 남아있었기 때문이다.

돌려본 회원 가입 Test도 spring이라는 이름으로 test를 하기 때문에 에러가 나는 것이다.

따라서 db의 데이터를 완전히 지워주어야 한다.

이렇게 member를 지워주었고,

다시 실행해보았더니
이렇게 모든 데이터가 삭제된 모습으로 나온다.

이 상태에서 다시 test를 돌려보겠다.

드디어 회원가입 test가 돌아가는 것을 볼 수 있다.

또한 spring이 뜨는 것을 볼 수 있다.

이전 test에서는 spring이 뜨지 않았었는데 말이다.

다시 MemberServiceIntegrationTest 코드로 돌아가서,
@Transactional이 필요한 이유를 알아보기 위해
@Transactional을 주석 처리 해 보았다.

그리고 실행시켜보았는데 제대로 돌아간다.

db도 돌려보았더니

이렇게 spring이 뜨는 것을 볼 수 있다.

*ID 값은 이전 기록까지 모두 포함하여 더해지기 때문에 member를 삭제해도 계속해서 값이 올라간다.

그런데
test는 반복할 수 있어야 한다고 했었다.

db 내용을 삭제하고 처음 한 번 돌려보았을 땐 실행도 잘 되고
오류도 뜨지 않았었는데
다시 돌려보았더니,

이미 존재하는 회원이라는 경고가 다시 뜬다.

이미 spring이 db에 존재하고 있기 때문이다.

그러면 어떻게 해야할까?

또 @AfterEach @BeforeEach 를 만들어서 지워야할까?

db는 기본적으로 transaction이라는 개념이 있다.

그래서 db에 data를 insertquery 한 다음에 commit을 해주어야 db에 반영이 된다.

그리고 test가 끝나면 rollback을 해주어야 되는데,

"@Transactional을 test case에 달면
test를 실행할 때, transaction을 먼저 하고
db에 data를 insertquery 해주고
test가 끝나면 rollback을 해준다."

그래서 db의 데이터가 반영이 안되고 깔끔하게 모두 지워진다.

아까 주석 처리 해놨던 @Transactional을 다시 활성화 시키고,
db의 member를 일단 delete from member 시켜놓고
회원가입 test를 돌려 보았더니
이렇게 실행이 제대로 된다.

그리고 db를 확인해보았더니,

delete한 그대로 아무 data도 저장되어 있지 않은 것을 볼 수 있다.

Transaction이 rollback을 해주어서 data가 db에 반영되지 않았기 때문이다.

그래서 test case를 무한대로 돌려볼 수 있게 되는 것이다.

두 번 세 번 더 돌려봐도 db에는 아무 data가 저장되어 있지 않은 모습을 확인할 수 있다.

정리

  • @SpringBootTest : 스프링 컨테이너와 테스트를 함께 실행한다. → 진짜 스프링을 띄워서 테스트를 하는 것
  • @Transactional : 테스트 케이스에 이 애노테이션이 있으면, 테스트 시작 전에 transaction을 시작하고, 테스트 완료 후에 항상 롤백한다.(test 시작할 때마다 실행된다) 이렇게 하면 db에 데이터가 남지 않으므로 다음 테스트에 영향을 주지 않는다.

그러면 이제 MemberServiceTest처럼 순수하게 자바 코드로 작성하면서,
최소한의 단위로 하는 단위 test는 필요가 없지 않느냐 는 의문이 들 수 있다.

그런데 MemberServiceTest와 MemberServiceIntegrationTest를
둘 다 실행시켜보면, 결과가 뜨는 시간이 매우 차이가 난다는 것을 알 수 있다.

MemberServiceTest는 실행되는 시간이 매우 짧다.

스프링 컨테이너와 db까지 연동하는
통합 test(MemberServiceIntegrationTest)가 아니기 때문이다.

사실은
순수한 단위 test가 더 좋은 test일 확률이 높다.

스프링 컨테이너 없이 test 할 수 있도록 훈련을 해야 한다.

0개의 댓글