inflearn logo
강의

강의

N
챌린지

챌린지

멘토링

멘토링

N
클립

클립

로드맵

로드맵

지식공유

Spring Data Jpa에서 flush()는 어떻게 하나요?

1612

제이콥

작성한 질문수 2

0

일단 저의 전체 코드입니다.

 

package com.readingbooks.web.service.member;

import com.readingbooks.web.domain.enums.Gender;
import com.readingbooks.web.exception.member.MemberPresentException;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.transaction.annotation.Transactional;

import static org.assertj.core.api.Assertions.assertThat;
import static org.assertj.core.api.Assertions.assertThatThrownBy;

@SpringBootTest
@Transactional
class MemberServiceTest {
    @Autowired
    private MemberService memberService;
    
    @Test
    void register_fail_null(){
        RegisterRequest request = createRequest(null, null, null, null, null, null);
        assertThatThrownBy(
                ()-> memberService.register(request))
                .isInstanceOf(IllegalArgumentException.class);
    }

    @Test
    void register_fail_invalid_email(){
        RegisterRequest request = createRequest("tes@example.com", "test1234", "test", "1999", "01012341234", Gender.SECRET);
        assertThatThrownBy(()->memberService.register(request))
                .isInstanceOf(IllegalArgumentException.class)
                .hasMessageContaining("이메일을 올바르게 입력해주세요.");

    }

    @Test
    void register_fail_invalid_short_password(){
        RegisterRequest request = createRequest("test@example.com", "test", "test", "1999", "01012341234", Gender.SECRET);
        assertThatThrownBy(()->memberService.register(request))
                .isInstanceOf(IllegalArgumentException.class)
                .hasMessageContaining("비밀번호를 올바르게 입력해주세요. 비밀번호는 8-16자에 특수문자 '@, $, !, %, *, #, ?, &'가 포함되야 합니다.");
    }

    @Test
    void register_fail_invalid_not_contained_password(){
        RegisterRequest request = createRequest("test@example.com", "test", "test1234", "1999", "01012341234", Gender.SECRET);
        assertThatThrownBy(()->memberService.register(request))
                .isInstanceOf(IllegalArgumentException.class)
                .hasMessageContaining("비밀번호를 올바르게 입력해주세요. 비밀번호는 8-16자에 특수문자 '@, $, !, %, *, #, ?, &'가 포함되야 합니다.");
    }

    @Test
    void register_fail_invalid_name(){
        RegisterRequest request = createRequest("test@example.com", "test1234", "t", "1999", "01012341234", Gender.SECRET);
        assertThatThrownBy(()->memberService.register(request))
                .isInstanceOf(IllegalArgumentException.class)
                .hasMessageContaining("이름을 올바르게 입력해주세요.");
    }

    @Test
    void register_fail_invalid_birthYear(){
        RegisterRequest request = createRequest("test@example.com", "test1234!", "test", "19990115", "01012341234", Gender.SECRET);
        assertThatThrownBy(()->memberService.register(request))
                .isInstanceOf(IllegalArgumentException.class)
                .hasMessageContaining("생년을 올바르게 입력해주세요.");
    }

    @Test
    void register_fail_invalid_phoneNo(){
        RegisterRequest request = createRequest("test@example.com", "test1234!", "test", "1999", "0101234", Gender.SECRET);
        assertThatThrownBy(()->memberService.register(request))
                .isInstanceOf(IllegalArgumentException.class)
                .hasMessageContaining("핸드폰 번호를 올바르게 입력해주세요.");
    }

    @Test
    void register_fail_invalid_gender(){
        RegisterRequest request = createRequest("test@example.com", "test1234!", "test", "1999", "01012341234", null);
        assertThatThrownBy(()->memberService.register(request))
                .isInstanceOf(IllegalArgumentException.class)
                .hasMessageContaining("성별을 올바르게 입력해주세요.");
    }

    @Test
    void register_fail_present_email(){
        //given
        RegisterRequest registerMember = createRequest("test@example.com", "test1234!", "test", "1999", "01012341234", Gender.SECRET);
        memberService.register(registerMember);

        RegisterRequest request = createRequest("test@example.com", "test1234", "test", "1999", "01012341234", Gender.MEN);

        assertThatThrownBy(() -> memberService.register(request))
                .isInstanceOf(MemberPresentException.class)
                .hasMessageContaining("이미 가입된 이메일입니다.");
    }

    @Test
    void register_success(){
        //given
        RegisterRequest registerMember = createRequest("success@example.com", "test1234!", "test", "1999", "01012341234", Gender.SECRET);

        //when
        Long memberId = memberService.register(registerMember);

        //then
        assertThat(memberId).isEqualTo(1L);
    }

    private RegisterRequest createRequest(String email, String password, String name, String birthYear, String phoneNo, Gender gender){
        return new RegisterRequest(email, password, name, birthYear, phoneNo, gender);
    }

}

문제의 메소드는 register_success입니다. 메소드 단위 테스트를 진행할 때는 아무런 문제가 되지 않지만, 메소드 전체를 한번에 테스트를 진행할 때

org.opentest4j.AssertionFailedError:

expected: 1L

but was: 2L

예외가 터집니다.

테스트 코드에서는 h2 인메모리 db를 사용하고 있습니다. 분명 @Transactional 애노테이션까지 붙여서 롤백될텐데 왜 롤백이 안 되는지 ㅠㅠ..

그래서 생각한 건 테스트 코드에 @beforeEach 애노테이션으로 영속성 컨텍스트를 flush 시키는 방법인데, 현재 저는 Spring Data Jpa를 사용하고 있어서 entityManager.flush()를 사용하기에는 애로사항이 있습니다.

public interface MemberRepository extends JpaRepository<Member, Long> {
    Optional<Member> findByEmail(String email);
}
@DirtiesContext(classMode = DirtiesContext.ClassMode.BEFORE_EACH_TEST_METHOD)

테스트코드에 위의 애노테이션을 붙이는 방법도 있던데, 이렇게 하면 메소드를 실행할 때마다 컨텍스트를 초기화해서 너무 느리더라고요.

 

어떻게 하면 좋을까요?

springdatajpa jpa java

답변 1

0

인프런 AI 인턴

안녕하세요, 인프런 AI 인턴이에요.

Spring Data JPA에서 flush() 메서드는 EntityManager 인터페이스를 구현한 EntityManagerFactory의 createEntityManager() 메서드를 통해 EntityManager를 생성 후, EntityManager의 flush() 메서드를 이용해서 사용할 수 있습니다.

즉, EntityManager 객체를 생성 후, 해당 EntityManager의 flush() 메서드를 호출하면 영속성 컨텍스트의 상태를 데이터베이스에 동기화할 수 있습니다.

그리고 보시면 Test 클래스에서 @Transactional 어노테이션이 선언되어 있는데, 이것은 해당 메서드가 호출된 후에 자동으로 롤백된다는 의미입니다. 따라서, flush() 메서드 호출 후에 롤백된 상태로 동작하기 때문에 해당 메서드를 테스트하기 어려울 수 있습니다.

해결 방법으로는, @Transactional 어노테이션을 클래스 수준에서 선언하거나, flush() 메서드 호출 이후에 테스트를 진행하는 다른 메서드를 추가하는 것입니다.

참고하시기 바랍니다. 감사합니다.

어플리케이션 실행 후 에러에 관하여 질문 드립니다.

0

7

1

업캐스팅 문제 예시 5

0

6

1

(기출) 2025년 2회 이론 파트

0

10

1

RestTemplate과 webClient, RestClient에 대해서 질문드립니다.

0

6

0

26년 1회실기

0

16

1

강의 자료

0

20

1

setter 사용하지 않기

0

18

1

27:15 break 출력

0

18

1

세션을 제대로 이해한게 맞는지 궁금합니다

0

17

1

55강 파이썬에만있는 연산자들

0

36

2

55강의 파이썬에서만 있는 연산자들

0

25

2

안녕하세요 토비님 혹시 완성된 코드의 repository 주소는 없을까요?

0

34

2

강의 영상 업로드 질문

0

40

2

자막 오타 제보

0

31

1

운영환경에 적용해볼 수 없을때...고민입니다 ㅠㅠ

0

33

1

13 섹션 병렬 스트림 고급 1탄 매치 문의

0

39

2

rabbitmq에 configservice 연결에 대해 질문있습니다.

0

34

1

29강 5:00

0

34

2

3차원 배열의 인덱스 해석 순서와 3중 반복문 순회 메커니즘에 대해 질문드립니다.

0

26

1

인텔리제이 설정 최신화 관련 확인 부탁 드립니다!

1

50

2

띄어쓰기

0

42

2

공부 순서

1

52

2

코딩 문제 사이트 접속 오류

0

28

1

재귀함수 연산법

0

33

2