ABOUT ME

-

오늘
-
어제
-
-
  • JPA - Common Repository
    Back-end/JPA 2020. 6. 30. 17:03

    Repository

    Repository에는 4가지의 종류가 있습니다.

    • Common
    • Repository : 일반적인 Marker
    • CrudRepository : CRUD 오퍼레이션 제공
    • PagingAndSortingRepository : 페이지와 정렬
    • JPA
    • JpaRepository : Jpa 활용시 사용

    이중 Common에 해당되는 Repository를 학습해보겠습니다.
    기존 Post 엔티티 클래스와 Repository를 활용할 것이므로 이전 포스팅, JPA 원리 포스팅을 참고해주시면 되겠습니다.

    Repository 테스트

    임베디드 DB 추가

            <dependency>
                <groupId>com.h2database</groupId>
                <artifactId>h2</artifactId>
                <scope>test</scope>
            </dependency>

     

    Repository

    로컬 데이터에 간섭하지 않고 테스트를 하기 위해 테스트 H2를 추가합니다.

    Test 클래스

    @RunWith(SpringRunner.class)
    @DataJpaTest
    public class PostRepositoryTest {
    
        @Autowired
        PostRepository postRepository;
    
        @Test
        public void crudRepository() {
            /* Given - 이런 조건에서 */
            Post post = new Post();
            post.setTitle("hello spring boot common");
            assertThat(post.getId()).isNull(); /* Trasient 상태이므로 Null입니다 */
    
            /* When - 이렇게 했을 때 */
            Post newPost = postRepository.save(post); /* post를 저장합니다. */
    
            /* Then - 이렇게 되길 바란다 */
            assertThat(newPost.getId()).isNotNull(); /* Persist 상태이므로 Null이 아닙니다 */
        }
    }

     

    Repository

    Post 클래스에 대한 Repository를 주입 받고 제목을 추가한 다음 Null인지 테스트 하는 로직입니다.

    Repository

    위 로직을 실행시키면 테이블은 생성되지만 위 결과처럼 insert가 되지 않고 Id만 찾는 것을 알 수 있습니다.

    그 이유는 H2는 기본적으로 @Transactional이 붙어있으면 기본적으로 테스트를 Rollback하기 때문에 Hibernate에서는 Rollback한 데이터를 insert할 필요 없다고 판단한 것입니다. 여기서 Transactional은 Spring이 자동으로 실행되는 것입니다.
    그렇다면 테스트에서 Rollback을 적용하지 않으려면 어떻게 해야할까요?

    @Rollback(false)

    @RunWith(SpringRunner.class)
    @DataJpaTest
    public class PostRepositoryTest {
    
        @Autowired
        PostRepository postRepository;
    
        @Test
        @Rollback(false)
        public void crudRepository() {
            /* Given - 이런 조건에서 */
            Post post = new Post();
            post.setTitle("hello spring boot common");
            assertThat(post.getId()).isNull(); /* Trasient 상태이므로 Null입니다 */
    
            /* When - 이렇게 했을 때 */
            Post newPost = postRepository.save(post); /* post를 저장합니다. */
    
            /* Then - 이렇게 되길 바란다 */
            assertThat(newPost.getId()).isNotNull(); /* Persist 상태이므로 Null이 아닙니다 */
        }
    }

     

    Repository

    @Rollback(false)을 통해 Hibernate가 insert할 수 있도록 합니다.

    Repository

    짜잔! Hibernate가 Rollback이 안되는걸 알아채고 insert를 했습니다.

    CrudRepository

    대표적으로 FindAll()을 활용하여 테스트해보겠습니다.

            /* When */
            List<Post> posts = postRepository.findAll();
    
            /* Then */
            assertThat(posts.size()).isEqualTo(1);
            assertThat(posts).contains(newPost);

     

    Repository

    Repository에 있는 post를 찾아서 List에 담고 1개가 맞는지, newPost에 포함되어 있는지 테스트합니다.

    Repository

    테스트가 성공하면 이전에 넣었던 Post를 출력합니다.

    PagingAndSortingRepository

    페이지를 이용하여 테스트를 해보겠습니다.

            /* When */
            Page<Post> page = postRepository.findAll(PageRequest.of(0, 10));
    
            /* Then */
            assertThat(page.getTotalElements()).isEqualTo(1);
            assertThat(page.getNumber()).isEqualTo(0);
            assertThat(page.getSize()).isEqualTo(10);
            assertThat(page.getNumberOfElements()).isEqualTo(1);

     

    Repository

    PageRequest.of()를 사용하여 시작페이지, 최대페이지를 설정할 수 있습니다. 이렇게 설정한 페이지는 Page라는 도메인으로 만들어지고 이를 활용할 수 있습니다.

    • getTotalElements() : 전체 페이지 개수
    • getNumber() : 현제 페이지 넘버
    • getSize() : 요청했던 페이지 사이즈
    • getNumberOfElements() : 현재 페이지에 들어올 수 있는 개수

    Custom 메소드 추가

    Custom한 메소드를 추가해서 자신이 원하는 테스트를 진행할 수 있습니다.
    참고자료 : 스프링공식문서

    FindAll() Custom 메소드

    import org.springframework.data.domain.Page;
    import org.springframework.data.domain.Pageable;
    import org.springframework.data.jpa.repository.JpaRepository;
    
    public interface PostRepository extends JpaRepository<Post, Long> {
    
        Page<Post> findByTitleContains(String title, Pageable pageable);
    }

     

    Repository

    제목이 포함된 페이지를 찾는 메소드입니다. 제목과 페이지를 가져와야하기 때문에 제목, 페이지를 파라미터로 가져옵니다.

    page = postRepository.findByTitleContains("spring", PageRequest.of(0, 10));
    
    assertThat(page.getTotalElements()).isEqualTo(1);
    assertThat(page.getNumber()).isEqualTo(0);
    assertThat(page.getSize()).isEqualTo(10);
    assertThat(page.getNumberOfElements()).isEqualTo(1);

     

    Repository

    Spring이 포함된 제목과 0~10 페이지 사이의 데이터를 가져옵니다.

    기타 Custom 메소드

    FindAll() 뿐만 아니라 다양하게 Custom이 가능합니다.

    public interface PostRepository extends JpaRepository<Post, Long> {
    
        long countByTitleContains(String title);
    }

    Title이 포함되면 카운트 하는 메소드입니다.

    /* When - spring을 가지고 있는 개수를 모두 센다 */
    long spring = postRepository.countByTitleContains("spring");
    /* Then - 개수는 1이다 */
    assertThat(spring).isEqualTo(1);

    spring이 포함된 제목을 모두 카운팅 해서 spring에 담고 테스트를 진행합니다.

    'Back-end > JPA' 카테고리의 다른 글

    JPA - Common Null  (0) 2020.06.30
    JPA - Common Interface  (0) 2020.06.30
    JPA - JPA의 원리  (0) 2020.06.30
    JPA - Query(쿼리)  (0) 2020.06.30
    JPA - FETCH  (0) 2020.06.30

    댓글