정렬 조건이 추가됐을 때 테스트 코드의 제약

리스트를 조회하는 API에는 정렬 조건이 추가되는 경우가 굉장히 많습니다.

그런데 API에 정렬 조건이 추가됐을 때 테스트 코드를 작성하다보면 자동으로 시간을 등록해주는 JPA의 기능인 @CreationTimestamp 와 @UpdateTimestamp 때문에 원하는 대로 테스트 코드를 작성하는데 제약이 생깁니다.

엔티티/서비스 코드

어떤 제약이 생기는지 바로 코드를 살펴보겠습니다. 먼저 JPA Auditing 이 적용된 엔티티를 만들어 보죠.

@Getter
@NoArgsConstructor(access = AccessLevel.PROTECTED)
@Entity
public class CreateDateOrder {

    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;

    @CreationTimestamp
    @Column(nullable = false, updatable = false)
    private LocalDateTime createDate;

    @UpdateTimestamp
    @Column(insertable = false)
    private LocalDateTime updateDate;

    @Builder
    private CreateDateOrder(LocalDateTime createDate, LocalDateTime updateDate) {
        this.createDate = createDate;
        this.updateDate = updateDate;
    }

    public static CreateDateOrder createEntity() {
        return CreateDateOrder.builder()
                .build();
    }

}

그리고 테스트 코드를 작성하기 위해 간단하게 저장과 생성시간 내림차순 조회하는 서비스 로직을 만들어봅시다.

@Service
@RequiredArgsConstructor
public class CreateDateOrderService {

    private final CreateDateOrderRepository createDateOrderRepository;

    public Long save(){
        CreateDateOrder saved = createDateOrderRepository.save(CreateDateOrder.createEntity());
        return saved.getId();
    }

    public List<CreateDateOrder> findAll(){
        return createDateOrderRepository.findAllByOrderByCreateDateDesc();
    }

}

테스트 코드

이제 여러개를 저장한 후에 생성시간 내림차순으로 조회하는 테스트 코드를 작성해볼까요?

@Transactional
@SpringBootTest
class CreateDateOrderOrderServiceTest {

    @Autowired
    private CreateDateOrderService createDateOrderService;

    @DisplayName("동시에 여러개 저장 - 실패 케이스")
    @Test
    void saveFail() {
        //given
        Long id1 = createDateOrderService.save();
        Long id2 = createDateOrderService.save();
        Long id3 = createDateOrderService.save();
        Long id4 = createDateOrderService.save();
        Long id5 = createDateOrderService.save();
        Long id6 = createDateOrderService.save();

        //when
        List<CreateDateOrder> results = createDateOrderService.findAll();

        //then
        assertThat(results).hasSize(6)
                .extracting("id")
                .containsExactly(id6, id5, id4, id3, id2, id1);
    }
    
}

분명 순서대로 저장이 된다면 테스트가 성공할 것 같지만 예상과 다르게 실패합니다.

image.png

실패하는 이유는 단순히 컴퓨터의 처리 속도 차이로 인해, 같은 시간에 여러 데이터의 생성 시간이 기록되는 경우가 발생했기 때문입니다.