카테고리 없음

JUnit 단위 테스트코드에서 Transactional을 써도 될까?

나는 나야 2024. 4. 10. 13:11

최근 API를 개발하다 너무 복잡하게 얽힌 코드들로 인해 프로젝트 여기저기 다니면서 확인하고, 최종적으로는 Postman이라는 프로그램으로 테스트를 진행했어야 했습니다. 물론, Produntion에 올리기 전에는 최종적으로 확인을 해야하지만, 개발 중간중간에 몇 번이고 Postman으로 테스트하는 건 정말 시간이 아깝다고 생각했습니다. 그래서 테스트코드를 공부하고 작성한 코드의 명백함을 보장하기 위해서 테스트 코드를 작성하고 있습니다.

 

주제에 대한 테스트는 아래의 코드와 같습니다.

 @DisplayName("회사 등록 시 필요한 정보가 모두 저장되는지 검증한다.")
    @Test
    void registerCorporation() {
        // given
        List<String> jobList = List.of("JOB1", "JOB2", "JOB3");

        RegisterCorporation registerCorporation = RegisterCorporation.builder()
                .name("구글")
                .startDate(LocalDateTime.of(2024, 4, 30, 12, 30))
                .endDate(LocalDateTime.of(2024, 5, 30, 12, 30))
                .tasksList(jobList)
                .build();

        // when
        corporationsService.registerCorp(registerCorporation);

        // then
        List<Corporations> corporationsList = corporationsRepository.findAll();
        assertThat(corporationsList)
                .extracting("name", "startDate", "endDate")
                .containsExactlyInAnyOrder(
                        tuple("구글",
                                LocalDateTime.of(2024, 4, 30, 12, 30),
                                LocalDateTime.of(2024, 5, 30, 12, 30)));

        List<String> storedJobs = corporationsList.get(0).getTasksList().stream()
                .map(Tasks::getJob)
                .collect(Collectors.toList());
        assertThat(storedJobs).containsExactlyInAnyOrderElementsOf(jobList);
    }

 

이러한 간단한 테스트를 진행하면서 저장된 jobList들이 올바르게 들어갔는지 확인하고 싶었습니다.

 

잘 작성했다고 생각하고 테스트를 돌리는 순간??!! 

 

org.hibernate.LazyInitializationException: failed to lazily initialize a collection of role: co
http://m.gathering.info.info.domain.corporations.entity.Corporations.tasksList:
 could not initialize proxy - no Session

 

org.hibernate.LazyInitializationException 오류는 Hibernate에서 흔히 발생하는 문제 중 하나로, 지연 로딩(Lazy Loading)을 사용하는 엔티티의 프로퍼티에 접근할 때, 해당 엔티티를 로드한 세션이 이미 닫혀 있을 때 발생합니다. 지연 로딩은 연관된 엔티티나 컬렉션이 실제로 필요할 때까지 로딩을 미루는 방식으로, 성능 최적화에 유용하게 사용됩니다. 그러나, 엔티티를 로드한 세션(Hibernate 세션)이 닫힌 후에 연관된 엔티티나 컬렉션에 접근하려고 하면, LazyInitializationException이 발생합니다.

 

LazyInitializationException이 발생했습니다.

 

@Transactional을 추가하면 되지만, 고민이 된 건 추가해서 단위테스트를 진행해도 될까? 이었습니다.

 

코드로 본다면, 아래와 같습니다.

 

    @DisplayName("회사 등록 시 필요한 정보가 모두 저장되는지 검증한다.")
    @Test
    @Transactional
    void registerCorporation() {
        // given
        List<String> jobList = List.of("JOB1", "JOB2", "JOB3");

        RegisterCorporation registerCorporation = RegisterCorporation.builder()
                .name("구글")
                .startDate(LocalDateTime.of(2024, 4, 30, 12, 30))
                .endDate(LocalDateTime.of(2024, 5, 30, 12, 30))
                .tasksList(jobList)
                .build();

        // when
        corporationsService.registerCorp(registerCorporation);

        // then
        List<Corporations> corporationsList = corporationsRepository.findAll();
        assertThat(corporationsList)
                .extracting("name", "startDate", "endDate")
                .containsExactlyInAnyOrder(
                        tuple("구글",
                                LocalDateTime.of(2024, 4, 30, 12, 30),
                                LocalDateTime.of(2024, 5, 30, 12, 30)));

        List<String> storedJobs = corporationsList.get(0).getTasksList().stream()
                .map(Tasks::getJob)
                .collect(Collectors.toList());
        assertThat(storedJobs).containsExactlyInAnyOrderElementsOf(jobList);
    }

 

이렇게 되면 충분히 테스트코드가 통과가 됩니다.

 

고민의 결과부터 말씀드리면 'Transaction을 사용했을 때 부가적인 영향만 파악하고 있으면, 충분히 써도 될 것 같다' 입니다.

 

Transaction을 추가했을때 본 코드와 테스트 코드 간의 차이로 인해서 테스트 코드는 통과가 되지만, 본 코드를 실행하고, 서비스를 제공하면서 발생할 수 있는 에러에 대한 차이점이라고 생각했습니다.

 

본 코드에는 다시 연관된 List를 조회하는 코드가 없고, 이미 Service 단에는 Transaction이 걸려있습니다. 때문에, 테스트 코드에 Transaction 을 추가한다고 해서 본 코드에 영향이 없다고 생각해서 사용하여 테스트를 진행하는 것으로 결정하였습니다.