Entity에 Validation 코드를 넣기
Entity에 다음과 같이 Validation을 적용해줬습니다.

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

Column(nullable = false) vs @NotNull 확인 해보기
@Column(nullable = false)와 @NotNull의 차이점을 눈으로 확인해보겠습니다.
- @Column(nullable = false)


javax.persistence.PersistenceException
이 발생합니다.- @NotNull

쿼리가 날라가지 않고
javax.validation.ConstraintViolationException
이 발생합니다.Entity 클래스가 많은 어노테이션으로 지저분한 감이 없지 않아 있지만 개인적으로는 꽤나 괜찮은 것 같습니다.
Entity를 중심으로 핵심 비즈니스 로직들이 동작하는 SpringBoot + JPA에서는 Entity에 모든 Validation을 몰아주는 것이 유효성 검사 측면에서 효율적이고 안정적이지 않을까? 라는 생각이 듭니다.
문제 발생
하지만 테스트할 때에 문제를 겪고 있습니다.
Service 통합테스트에서는 트랜잭션을 사용하고, 테스트 코드에서는 commit을 지연시키고 테스트 종료 시 roll back을 하는데요 그래서 다음과 같이 예외가 발생하기를 기대했지만 예외가 발생하지 않는 문제가 발생합니다.


예외를 기대했지만 예외가 발생하지 않았다는 것이죠
그렇다고 실제로 예외를 발생하지 않는것은 아닙니다. 포스트맨으로 확인 시 ControllerAdvice에서 예외가 확실하게 잡히는 것으로 보입니다.
그 예외 발생 시점은 영속성 계층에서 flush가 이루어질 때 입니다.


그렇다면
@Rollback(false)
또는 @Commit
을 추가해서 커밋이 되도록 하면 되지 않을까? 생각을 하고 테스트 코드를 변경해봤습니다.

하지만 뭔가 이상합니다. 예외는 발생했지만 테스트코드에서 예외를 잡을 수 없는데요.
이 문제를 어떻게 바라봐야할지 아직 감이 잡히지 않습니다.
에러 로그를 살펴보면 다음과 같은 메시지가 있습니다.

afterTestMethod
를 수행하는 도중 예외가 잡혔다는 말 같은데요.afterTestMethod
는 예상컨데 테스트 코드 본문이 끝나고 Commit
또는 Rollback
을 하는 별개의 단계인것 같습니다.마치 데코레이터 패턴처럼 다음과 같이 테스트 본문 전처리, 후처리 메서드가 실행되고 후처리 메서드에서는
Commit
을 하거나 Rollback
을 한다는 것이죠- 테스트 전 method (존재하지 않을 수도?)
- 테스트 본문 method (사용자가 작성한 test method)
- 테스트 후 method (Commit 수행)
그렇다면 테스트 코드에서 테스트가 발생하지 않았지만 발생한(?) 문제에 대해서 어느정도 설명할 수 있을 것 같습니다. 정확하지는 않아요.. 디버깅 해봐야함 ㅜㅜ
아무것도 모르는 응애는 이 문제를 어떻게 해결해야 할지 감이 잡히지 않습니다. 팀원분들이 도와주세요!🥲
디버깅 시도

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를 직접사용 해도되는가?(사용하는 것을 본적이없음..)