Skip to the content.

JPA Entity 테스트 가이드

목적: JPA Entity 단위 테스트 가이드


1️⃣ 테스트 전략

핵심 원칙

JPA Entity는 단위 테스트가 거의 불필요합니다!

이유:

테스트 범위

다른 레이어 테스트


2️⃣ 단위 테스트 (선택적)

언제 작성하는가?

테스트 구조

@DisplayName("OrderJpaEntity Unit Test")
class OrderJpaEntityTest {

    @Test
    @DisplayName("of() 메서드 호출 시 모든 필드가 정확히 설정되어야 한다")
    void of_WhenCalled_ShouldSetAllFieldsCorrectly() {
        // Given
        Long id = 1L;
        String orderNumber = "ORD-2025-001";
        OrderStatus status = OrderStatus.PENDING;
        Long userId = 100L;
        LocalDateTime createdAt = LocalDateTime.of(2025, 1, 1, 0, 0);
        LocalDateTime updatedAt = LocalDateTime.of(2025, 1, 2, 0, 0);

        // When
        OrderJpaEntity order = OrderJpaEntity.of(
            id, orderNumber, status, userId, createdAt, updatedAt
        );

        // Then
        assertThat(order.getId()).isEqualTo(id);
        assertThat(order.getOrderNumber()).isEqualTo(orderNumber);
        assertThat(order.getStatus()).isEqualTo(status);
        assertThat(order.getUserId()).isEqualTo(userId);
        assertThat(order.getCreatedAt()).isEqualTo(createdAt);
        assertThat(order.getUpdatedAt()).isEqualTo(updatedAt);
    }

    @Test
    @DisplayName("of() 메서드에 null ID 전달 시 null로 설정되어야 한다 (신규 생성)")
    void of_WhenIdIsNull_ShouldAllowNullId() {
        // Given
        String orderNumber = "ORD-2025-001";
        Long userId = 100L;
        LocalDateTime now = LocalDateTime.now();

        // When
        OrderJpaEntity order = OrderJpaEntity.of(
            null, orderNumber, OrderStatus.PENDING, userId, now, now
        );

        // Then
        assertThat(order.getId()).isNull();  // 신규 생성 시 ID는 null
        assertThat(order.getOrderNumber()).isEqualTo(orderNumber);
        assertThat(order.getUserId()).isEqualTo(userId);
    }

    @Test
    @DisplayName("BaseAuditEntity 상속 시 부모 필드도 정확히 설정되어야 한다")
    void of_WhenBaseAuditEntityInherited_ShouldSetParentFields() {
        // Given
        LocalDateTime createdAt = LocalDateTime.of(2025, 1, 1, 0, 0);
        LocalDateTime updatedAt = LocalDateTime.of(2025, 1, 2, 0, 0);

        // When
        OrderJpaEntity order = OrderJpaEntity.of(
            1L, "ORD-2025-001", OrderStatus.PENDING, 100L, createdAt, updatedAt
        );

        // Then
        assertThat(order.getCreatedAt()).isEqualTo(createdAt);
        assertThat(order.getUpdatedAt()).isEqualTo(updatedAt);
    }
}

3️⃣ SoftDeletableEntity 테스트

deletedAt 필드 설정 검증

@DisplayName("ProductJpaEntity Unit Test (SoftDeletableEntity)")
class ProductJpaEntityTest {

    @Test
    @DisplayName("of() 메서드 호출 시 deletedAt이 null이어야 한다 (활성 상태)")
    void of_WhenCalled_ShouldSetDeletedAtToNull() {
        // Given
        LocalDateTime now = LocalDateTime.now();

        // When
        ProductJpaEntity product = ProductJpaEntity.of(
            1L,
            "Product Name",
            now,
            now,
            null  // deletedAt
        );

        // Then
        assertThat(product.getDeletedAt()).isNull();
    }

    @Test
    @DisplayName("deletedAt이 설정되면 삭제 상태로 생성되어야 한다")
    void of_WhenDeletedAtSet_ShouldCreateAsDeleted() {
        // Given
        LocalDateTime now = LocalDateTime.now();
        LocalDateTime deletedAt = now.plusDays(1);

        // When
        ProductJpaEntity product = ProductJpaEntity.of(
            1L,
            "Product Name",
            now,
            now,
            deletedAt
        );

        // Then
        assertThat(product.getDeletedAt()).isEqualTo(deletedAt);
    }
}

4️⃣ 테스트하지 않는 것

❌ Getter 테스트

이유: 단순 필드 반환이므로 테스트 불필요

// ❌ 불필요한 테스트
@Test
void getId_ShouldReturnId() {
    OrderJpaEntity order = OrderJpaEntity.of(1L, 100L, now, now);
    assertThat(order.getId()).isEqualTo(1L);  // 의미 없음
}

❌ Setter 테스트

이유: Setter가 없음 (컨벤션 위반)

// ❌ Setter가 없으므로 테스트 불가
@Test
void setId_ShouldSetId() {
    // Setter가 없으므로 이 테스트 자체가 불가능
}

❌ 비즈니스 로직 테스트

이유: Entity에 비즈니스 로직 없음 (컨벤션 위반)

// ❌ 비즈니스 로직이 없으므로 테스트 불가
@Test
void approve_ShouldChangeStatusToApproved() {
    // approve() 메서드가 없음 (컨벤션 위반)
}

❌ JPA 매핑 테스트

이유: Repository 테스트에서 검증

// ❌ Entity 테스트에서 하지 않음
@DataJpaTest
class OrderJpaEntityJpaMappingTest {
    // JPA 매핑 검증은 Repository 테스트에서!
}

5️⃣ 디렉토리 구조

adapter-out/persistence-mysql/
├─ src/main/java/
│  └─ com/ryuqq/adapter/out/persistence/
│      ├─ order/
│      │  └─ entity/
│      │      └─ OrderJpaEntity.java
│      └─ common/entity/
│          ├─ BaseAuditEntity.java
│          └─ SoftDeletableEntity.java
│
└─ src/test/java/
   └─ com/ryuqq/adapter/out/persistence/
       ├─ architecture/entity/
       │  └─ JpaEntityArchTest.java  ⭐ ArchUnit (별도 문서)
       │
       └─ order/entity/
           └─ OrderJpaEntityTest.java  ⭐ 단위 테스트 (선택적)

6️⃣ 체크리스트

JPA Entity 테스트 작성 시:


7️⃣ 참고 문서


작성자: Development Team 최종 수정일: 2025-12-04 버전: 1.1.0