본문 바로가기
JPA

JPA로 인한 테스트 실패

by 고선제 2024. 8. 13.

안녕하세요, 개발자 여러분. 오늘은 JPA를 사용하면서 겪은 재미있는 문제 상황과 그 해결 과정을 공유하고자 합니다.

 

문제 상황

최근 프로젝트에서 JPA를 사용하여 엔티티의 soft delete 기능을 구현했습니다. @SQLDelete 어노테이션을 사용하여 삭제 쿼리를 커스터마이징하고, @SQLRestriction을 통해 삭제된 엔티티를 조회에서 제외하도록 설정했습니다.

 
 
그리고 다음과 같은 테스트 코드를 작성했습니다:
 
 

 

예상치 못한 결과

테스트를 실행했을 때, 예상과 다른 결과가 나왔습니다. isDeleted() 메서드가 false를 반환한 것입니다.

 

원인 분석

 

이 문제의 원인을 분석해보니, 다음과 같은 점들을 놓쳤다는 것을 깨달았습니다:

  1. 영속성 컨텍스트와 데이터베이스의 불일치: @SQLDelete는 데이터베이스 레벨에서 작동하지만, 영속성 컨텍스트의 엔티티 상태는 변경하지 않습니다.
  2. 캐시된 엔티티: 테스트에서 사용한 facility 객체는 여전히 영속성 컨텍스트에 캐시된 상태였고, 데이터베이스의 변경사항을 반영하지 않았습니다.

 

해결 방법

이 문제를 해결하기 위해 다음과 같은 접근 방식을 사용할 수 있습니다:

 

1. 영속성 컨텍스트 초기화

entityManager.flush();
entityManager.clear();

 

 

2. 네이티브 쿼리 사용
: @SQLRestriction을 우회하는 네이티브 쿼리를 사용하여 삭제된 엔티티를 조회합니다.

Facility deletedFacility = (Facility) entityManager.createNativeQuery(
            "SELECT * FROM facility WHERE name = :name", Facility.class)
        .setParameter("name", facility.getName())
        .getSingleResult();

-> @SQLRestriction 로 인해, where절에 is_deleted = false 구문이 포함되는 문제점으로 인해, 네이티브 쿼리로 조회합니다.

 

최종 테스트 코드 :

 

  @DisplayName("soft delete가 되는 것을 확인한다.")
  @Test
  void soft_delete() {
    // given
    Facility facility = FacilityFixture.createFacility();
    facilityJpaRepository.save(facility);
    // when
    facilityJpaRepository.delete(facility);
    entityManager.flush();
    entityManager.clear();
    // then
    Facility deletedFacility = (Facility) entityManager.createNativeQuery(
            "SELECT * FROM facility WHERE name = :name", Facility.class)
        .setParameter("name", facility.getName())
        .getSingleResult();

    Assertions.assertThat(facilityJpaRepository.findAll()).isEmpty();
    Assertions.assertThat(deletedFacility.isDeleted()).isTrue();
  }
 

교훈

이번 경험을 통해 몇 가지 중요한 교훈을 얻었습니다:

  1. JPA의 영속성 컨텍스트와 실제 데이터베이스 상태의 차이를 항상 인지해야 합니다.
  2. @SQLDelete와 같은 데이터베이스 레벨의 조작은 영속성 컨텍스트에 즉시 반영되지 않습니다.
  3. 테스트 시 entityManager.flush()와 clear()를 적절히 사용하여 영속성 컨텍스트를 관리해야 합니다.
  4. 복잡한 쿼리나 특수한 상황에서는 네이티브 쿼리 사용을 고려해볼 수 있습니다.

JPA는 강력한 도구이지만, 때로는 이런 세부적인 동작 방식 때문에 예상치 못한 결과를 마주할 수 있습니다. 이러한 경험들을 통해 JPA의 동작 원리를 더 깊이 이해하고, 더 나은 코드를 작성할 수 있게 되었습니다.

'JPA' 카테고리의 다른 글

OSIV와 지연로딩(feat. SSE)  (0) 2025.02.22