HomeAboutMeBlogGuest
© 2025 Sejin Cha. All rights reserved.
Built with Next.js, deployed on Vercel
🍗
[New] 조규현팀
/
🐾
DailyLog
/
Entity에 Validation 적용하고 테스트 코드 짜기

Entity에 Validation 적용하고 테스트 코드 짜기

태그
JPA
Validation
날짜
Jun 6, 2022 09:06 AM
해결 상태
완료
Thrower
Entity에 Validation 코드를 넣기이렇게 사용한 이유?Column(nullable = false) vs @NotNull 확인 해보기문제 발생디버깅 시도중간 결론

Entity에 Validation 코드를 넣기

Entity에 다음과 같이 Validation을 적용해줬습니다.
notion image

이렇게 사용한 이유?

DB에 쿼리를 날리기전에 ConstraintViolationException을 발생시켜 DB삽입 시 발생하는 Exception이 아닌 Validation 단계에서 사전에 예외를 발생시킨다는 점에서 꽤 매력을 느꼈습니다.
그리고 ddl에도 적용되어 @NotNull을 사용 시 db 제약 조건에도 not null 옵션을 자동으로 붙여줍니다. @Size도 마찬가지로 길이 제한도 ddl에 적용해줍니다.
notion image
 

Column(nullable = false) vs @NotNull 확인 해보기

@Column(nullable = false)와 @NotNull의 차이점을 눈으로 확인해보겠습니다.
  • @Column(nullable = false)
notion image
notion image
javax.persistence.PersistenceException이 발생합니다.
 
  • @NotNull
notion image
쿼리가 날라가지 않고 javax.validation.ConstraintViolationException이 발생합니다.
 
Entity 클래스가 많은 어노테이션으로 지저분한 감이 없지 않아 있지만 개인적으로는 꽤나 괜찮은 것 같습니다.
Entity를 중심으로 핵심 비즈니스 로직들이 동작하는 SpringBoot + JPA에서는 Entity에 모든 Validation을 몰아주는 것이 유효성 검사 측면에서 효율적이고 안정적이지 않을까? 라는 생각이 듭니다.
 

문제 발생

하지만 테스트할 때에 문제를 겪고 있습니다.
Service 통합테스트에서는 트랜잭션을 사용하고, 테스트 코드에서는 commit을 지연시키고 테스트 종료 시 roll back을 하는데요 그래서 다음과 같이 예외가 발생하기를 기대했지만 예외가 발생하지 않는 문제가 발생합니다.
notion image
notion image
예외를 기대했지만 예외가 발생하지 않았다는 것이죠
 
그렇다고 실제로 예외를 발생하지 않는것은 아닙니다. 포스트맨으로 확인 시 ControllerAdvice에서 예외가 확실하게 잡히는 것으로 보입니다.
그 예외 발생 시점은 영속성 계층에서 flush가 이루어질 때 입니다.
notion image
notion image
 
그렇다면 @Rollback(false)또는 @Commit을 추가해서 커밋이 되도록 하면 되지 않을까? 생각을 하고 테스트 코드를 변경해봤습니다.
notion image
notion image
 
하지만 뭔가 이상합니다. 예외는 발생했지만 테스트코드에서 예외를 잡을 수 없는데요.
이 문제를 어떻게 바라봐야할지 아직 감이 잡히지 않습니다.
 
에러 로그를 살펴보면 다음과 같은 메시지가 있습니다.
notion image
afterTestMethod를 수행하는 도중 예외가 잡혔다는 말 같은데요.
afterTestMethod는 예상컨데 테스트 코드 본문이 끝나고 Commit 또는 Rollback을 하는 별개의 단계인것 같습니다.
마치 데코레이터 패턴처럼 다음과 같이 테스트 본문 전처리, 후처리 메서드가 실행되고 후처리 메서드에서는 Commit을 하거나 Rollback을 한다는 것이죠
  • 테스트 전 method (존재하지 않을 수도?)
  • 테스트 본문 method (사용자가 작성한 test method)
  • 테스트 후 method (Commit 수행)
 
그렇다면 테스트 코드에서 테스트가 발생하지 않았지만 발생한(?) 문제에 대해서 어느정도 설명할 수 있을 것 같습니다. 정확하지는 않아요.. 디버깅 해봐야함 ㅜㅜ
 
아무것도 모르는 응애는 이 문제를 어떻게 해결해야 할지 감이 잡히지 않습니다. 팀원분들이 도와주세요!🥲
 

디버깅 시도

notion image
NodeTestTask Class의 executeRecursively()를 수행 한다. (뭔가 여러번 수행하는 듯?)
→ TestMethodTestDescriptor Class의 execute() 함수에서
invokeTestMethod()에서 테스트 코드 본문 수행(예외가 발생하지 않았음 Expecting code to raise a throwable 메시지와 함께 오류 발생.
 
→TestMethodTestDescriptor.execute()의 invokeAfterEachCallbacks() 에서
→ invokeAllAfterMethodsOrCallbacks()수행
→ 콜백 목록들 수행 중 TransactionSystemException 발생
 
아마도!
invokeTestMethod()에서 테스트 본문을 수행하고 테스트를 수행하고
invokeAfterEachCallbacks()에서 Commit을 하는것으로 추정..
 

중간 결론

  • @Commit이나 @Rollback(false)는 테스트 본문과 별개로 후처리 메서드에서 실행된다.
  • flush되는 시점에 예외가 발생하므로 테스트 본문에서 flush가 발생되도록 변경해야한다.
  • 통합테스트이므로 EntityManager를 가져와서 flush()를 수행하는 방안이 지금까지는 최선인듯?
    • 영속성 계층 테스트가아닌 Service 레이어 테스트에서 EntityManager를 직접사용 해도되는가?(사용하는 것을 본적이없음..)
    •