SpringBoot 테스트 DB가 초기화되지 않는다.

2022. 7. 31. 15:11Spring

문제

BDD의 Describe-Context-It 패턴을 이용해 테스트 코드를 작성하는 중이었다. 하지만 로직과 관련되지 않은 문제가 발생했다.

아래 사진은 문제를 발생시키는 테스트 코드이다.

현재 테스트 코드

이 코드가 통과되는 지 알아보자.

위 테스트 코드와 함께 보면 난 테스트 결과로 id가 1인 경우를 기대하고 있었으나 실제로 생성된 id는 6이라서 테스트가 실패했다는 것이다.

현재 deleteAll 메서드로 매 테스트마다 초기화를 해주고 있지만 auto_increment 는 초기화 되지 않는 것을 확인할 수 있다.

해결

이 문제를 해결하기 위해 다음 블로그를 참고했다. 참고 블로그

 

블로그의 내용을 보면 두 가지 방법이 있었다.

 

@Sql을 사용하는 방법과 auto_increment를 신경쓰지 않도록 테스트 코드를 작성하는 방법 이렇게 두 가지다.

이 방법들에 대한 내 생각은 다음과 같다.

  • @Sql 방법은
    • 모든 통합 테스트에 맞는 sql을 매번 작성해야 한다.
    • 테이블명, 필드가 바뀔 경우 찾아서 변경해야 한다.
    • @Nested 어노테이션이 있을 경우 사용하기 힘들다.
  • auto_increment를 신경쓰지 않거나 영향을 받지않도록 테스트 코드를 작성하는 방법은
    • 신경 쓰지 않을 경우 id 생성에 문제가 발생할 경우 캐치하기 힘들다.
    • findById 같이 id를 필요로하는 테스트처럼 id가 필요한 상황이 존재한다.

@Sql 방법으로 적용해보았다.

테스트 성공

@Sql 을 사용하니까 데이터를 완벽하게 초기화 할 수 있었다.

또 다른 문제

하지만 통과한 테스트는 맨 처음 상황과 테스트 구조를 다르게 작성한 상황이다. 다시 보면 계층형 테스트 구조(@Nested)를 사용하지 않은 것을 볼 수 있다.

그 이유는 내가 사용하던 @Nested에서 @Sql이 적용되지 않았기 때문이다.

 

또한 @DataJpaTest는 내부에 @Transactional을 가지고 있다. 그래서 테스트를 진행하고 DB를 롤백시키는 과정을 거치기에 deleteAll를 진행할 필요가 없다. 하지만 계층형 테스트 구조에서는 해당 어노테이션이 적용되지 않는 문제가 있다.

 

현재 이 문제는 해결 방법을 찾지 못햇기에 난 auto_increment를 신경쓰지 않거나 영향을 받지않도록 테스트 코드를 작성하는 방법을 선택했다.

 

테스트 DB가 초기화 되지 않는 문제는 deleteAll 을 사용했으며 영향을 받지 않는 테스트 코드를 만들기 위해서

위처럼 Toy를 생성시키고 Toy의 id를 가져와서 기대하는 Toy를 id를 파라미터에 넣어 만들어 같은 id임을 보장함으로써 id에 영향을 미치지 않는 코드를 작성했다.

 

계층형 테스트를 사용하지 않는 분들은 @Sql을 사용하시거나 영향을 받지 않도록 작성하시는 것도 좋을 듯하다.

 

나는 계층형 테스트에서 @Transactional@Sql을 적용해 사용하고 싶다. Give-When-Then 패턴보다 테스트를 논리적으로 설명하는 효과가 무척 뛰어나서 포기하고 싶지 않기 때문이다.

 

만약 해결한다면 다른 포스팅으로 작성해보겠다.

 

틀린 내용이 있는 경우, 댓글 남겨주시면 감사하겠습니다.