인프런 강의를 듣던 중 테스트 코드를 짜면서 특이한 에러를 마주했습니다.
"롤백을 해야만 한다고 지정되어서 트랜잭션이 롤백이 됐다" ??
우선 테스트 코드를 어떻게 짰는지 부터 알아보겠습니다.
@RunWith(SpringRunner.class)
@SpringBootTest
@Transactional
public class MemberServiceTest {
@Autowired
MemberService memberService;
@Autowired
MemberRepository memberRepository;
@Test
@Rollback(value = false)
public void join() throws Exception{
//given
Member member = new Member();
member.setName("Seungho");
//when
Long savedId = memberService.join(member);
//then
assertEquals(member, memberRepository.findOne(savedId));
assertEquals(member, memberService.findOne(savedId));
assertNotNull(member);
}
@Test
@Rollback(value = false)
public void duplicatedMember() throws Exception{
//given
Member member1 = new Member();
member1.setName("Seungho");
Member member2 = new Member();
member2.setName("Seungho");
//when
try{
memberService.join(member1);
memberService.join(member2);
}catch (IllegalStateException e){
assertEquals(e.getMessage(),"이미 존재하는 회원입니다.");
System.out.println(e.getMessage());
return;
}
//then
fail("예외가 안 발생해서 여기까지 오면 무조건 에러를 발생시키는 메소드. 즉 예외테스트 실패시 이 문장이 뜬다!");
}
}
우선 첫번째 join 테스트는 무난하게 성공할 수 밖에 없는 테스트 형식이고 두번째 duplicatedMember 메소드를 테스트코드 작성하기 위해 위에서 이미 Seungho라는 name으로 member 등록해놨던 아이디를 다시 중복되게 테스트 해봤습니다.
그러나 테스트 코드는 실패했고, 위에서 언급했던 "Transaction silently rolled back because it has been marked as rollback-only" 에러가 발생했습니다.
일단 문제는 직감했습니다.
@Rollback(value=false)라고 해놓은 부분인데요, 이 부분은 @Transaction에서 이루어지는 테스트 코드들이 default로 롤백이 되기 마련인데, 그 부분을 false로 지정해서 롤백을 안 하게 할려고 했었습니다.
그런데 try catch로 에러 처리를 해줌으로써 db에 저장은 안 돼도 에러가 나지 않고 테스트코드가 통과할 것 이라고 생각해서 관련된 에러를 찾아보던 중 이 블로그를 발견하고 문제를 이해했습니다.
위 두가지 이미지를 통해 보면 크게 "Exception"과 "Error"가 나뉘고 에러는 Unchecked Exception으로 예외 발생시 항상 롤백을 해야한다고 나와있습니다. 반면 예외는 Checked Exception으로 롤백 하지 않는다고 나와 있습니다.
제가 짠 코드에서는
//when
try{
memberService.join(member1);
memberService.join(member2);
}catch (IllegalStateException e){
assertEquals(e.getMessage(),"이미 존재하는 회원입니다.");
System.out.println(e.getMessage());
return;
}
이렇게 IllegalStateException을 날리고 있는데 이는 RuntimeException을 상속한 예외입니다. RuntimeException은 unchecked exception으로 분류되어 rollback을 해야한 하는데, @Rollback(value= false)로 롤백을 강제했으니 이 부분에서 위와 같은 에러가 발생한 것입니다.
이렇게 중복검사에 걸린 부분은 오히려 db에 저장이 안 되는 로직이 맞으니 위 코드에서 Rollback 어노테이셔만 지워주면 문제는 해결이 됩니다.
그러나 이런 어노테이션 문제가 아닌 문제로 문제가 발생한다면 앞서 언급한 블로그에 해결 방안도 제시 되어 있으니 참고하시길 바랍니다!