NoSuchElementError, AssertionError, findById()로 인한 Github Action CI 오류

문법식·2022년 2월 8일
0

진행 중인 Spring Boot프로젝트가 로컬에서 테스트를 돌리면 성공하는데 Github Action CI는 통과하지 못하는 오류가 발생한다는 팀원의 얘기를 듣고 해결을 도와주기로 했다.
Github Action CI에서는 NoSuchElement 오류 로그를 출력하고 있었다. 원인을 파악해보니 @BeforeEach 어노테이션, findById() 그리고 @GeneratedValue(strategy=GenerationType.IDENTITY) 때문에 복잡하게 발생한 오류였다. 상황을 정리하면 다음과 같다.

  • @BeforeEach 어노테이션이 붙은 테스트 데이터 저장 함수가 모든 테스트함수마다 실행한다.
  • 테스트함수에서 데이터베이스에 반영된 데이터들은 Transaction으로 롤백했지만, 자동 생성되는 아이디들의 시작 값은 롤백되지 않는다. 즉, 이후에 데이터를 데이터베이스에 저장하면 자동 생성된 아이디들의 시작값은 1이 아니라는 것이다.
  • 그러나, 각 테스트 함수의 코드는 테스트 데이터 저장 함수로 저장된 데이터의 아이디가 1에서부터 자동 생성되는 것으로 예상하고 작성되어 있었다.
  • 테스트 코드에서 예상한 아이디가 실제 데이터베이스에 저장된 데이터의 아이디와 다르므로 오류가 발생했다.

상황을 파악하고 나서 그렇다면 @BeforeEach가 아니라 @BeforeAll 어노테이션을 사용해서 테스트 데이터 저장 함수를 테스트 클래스에서 딱 한번만 실행하면 되지 않을까 생각했다. 위에서 얘기했듯이 지금의 문제는 똑같은 테스트 데이터들을 저장하는 함수가 @BeforeEach 어노테이션 때문에 모든 테스트 함수마다 실행되고 그로 인해 테스트 데이터들의 아이디가 예상한 아이디와 달라서 테스트 코드가 오류가 나는 것이기 때문이다. 테스트 클래스에서 딱 한번만 실행하면 테스트 함수 코드 작성 시 예상한 데이터의 아이디와 같기 때문에 오류가 안날 것이다. 그래서 @BeforeAll 어노테이션을 테스트 데이터 저장 함수에 사용했다.

로컬에서는 오류가 발생하지 않아서 Github로 푸시했으나 이번엔 AssertionError를 발생시켰다. 원인을 다시 파악해봤다. 생각해보니 Github는 테스트 클래스를 전부 다 한번에 실행해서 테스트를 한다. 하지만 나는 로컬에서 테스트 클래스마다 실행해보면서 테스트를 진행했다. 상황을 정리하면 다음과 같다.

  • Github Action CI는 테스트 클래스를 전부 한번에 실행해서 테스트를 진행한다. 위에서 얘기했듯이 Transaction 롤백을 해도 데이터베이스에 반영된 데이터는 지우지만, 자동 생성 아이디의 시작값은 롤백하지 않는다.
  • 즉, Github Action CI는 테스트 클래스를 전부 한번에 실행하기 때문에 테스트 DB인 H2에서 자동 생성되는 아이디는 클래스 단위로 다시 1부터 자동 생성되는 것이 아니라는 것이다.
  • 로컬에서는 내가 테스트를 클래스 단위로 돌렸기 때문에 오류가 발생하지 않는 것이었다.

위와 같은 상황을 파악하고 findById()가 아니라 findAll()을 사용해서 원하는 기능의 테스트 코드를 작성했다. 그리고 나서 나도 모든 테스트 클래스 한 번에 실행했고, 테스트를 통과해서 Github에 푸시하니 오류 없이 CI/CD가 잘 작동했다.

결론적으로 데이터베이스에 저장된 데이터의 아이디가 예상한 아이디와 달랐고 예상한 아이디를 바탕으로 짠 테스트 코드가 문제였다. 앞으로는 findById()로 테스트 코드를 짤 때 데이터의 아이디를 함부로 예상하지 말고 findAll()이나 다른 방법들을 저장된 데이터의 아이디를 한번 확인해보고 테스트 코드를 짜는 것이 안정적이라는 것을 깨달았다.

추가로 Github Action CI의 테스트 실행 단위도 알 수 있었다.

profile
백엔드

0개의 댓글