본문 바로가기
Back-End/Spring

[spring boot] JPA로 CRUD 테스트

by LeeGangEun 2022. 6. 10.

JpaRepository 인터페이스

package org.zeorck.ex2.repository;

import org.zerock.ex2.entity.Memo;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.stereotype.Repository;

@Repository
// JPA를 사용할 때는 엔티티의 타입정보(Memo)와 @Id 타입(Long)을 지정한다
// JPA는 인터페이스 선언만으로도 자동으로 스프링의 빈(Bean)으로 등록된다
public interface MemoRepository extends JpaRepository<Memo,Long> { // crud 사용가능 !											
}
  • insert 작업 : save(entity 객체)
  • select 작업 : finrById(key 타입), getOne(키 타입)
  • update 작업 : save(entity 객체)
  • delete 작업 : deleteById(키 타입), delete(entity 객체) 

insert와 update 작업에 사용하는 매서드가 동일한데,
이는 JPA의 구현체가 메모리상(Entity Manager 라는 존재가 entity들을 관리하는 방식)에서
객체를 비교하고 없다면 insert, 존재한다면 update를 동작시키는 방식으로 동작하기 때문이다.

테스트 클래스 생성

package org.zerock.ex2.repository;

import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Pageable;
import org.springframework.data.domain.Sort;
import org.springframework.test.annotation.Commit;
import org.zerock.ex2.entity.Memo;

import javax.transaction.Transactional;
import java.util.List;
import java.util.Optional;
import java.util.stream.IntStream;

@SpringBootTest
public class MemoRepositoryTests {
    @Autowired // 주입 @Inject가 표준임
    MemoRepository memoRepository;  //memoRepository 객체가 자동 생성됨

    @Test
    public void testClass(){
        System.out.println(memoRepository.getClass().getName()); 
    }

testClass() 메서드는 MemoRepository 인터페이스 타입의 실제 객체가 어떤 것인지 확인한다.
스프링이 내부적으로 해당 클래스를 자동으로 생성하는데(AOP)기능
이때의 클래스 이름을 확인해 보고자 하는 것이다.
테스트 코드는 'com.sun.proxy.$ProxyXX'와 같이 작성한 적이 없는 클래스의 이름이 출력되는 것을 확인할 수가 있다.
(동적 프록시 방식으로 만들어진다)

insert 테스트

@SpringBootTest
public class MemoRepositoryTests {
    @Autowired // 주입 @Inject가 표준임
    MemoRepository memoRepository;  //memoRepository 객체가 자동 생성됨
    
    @Test
    public void testInsertDummies(){
        IntStream.rangeClosed(1,100).forEach(i -> {
            Memo memo = Memo.builder().memoText("Sample..."+i).build();
            memoRepository.save(memo);
        });
    }
    
// 100개의 새로운 Memo 객체 생성 후
//MemoRepository를 이용해서 이를 insert하는 것이다.


*실행결과 - 100개의 더미 데이터가 저장되었다.*

조회 작업  테스트

  @SpringBootTest
public class MemoRepositoryTests {
    @Autowired // 주입 @Inject가 표준임
    MemoRepository memoRepository;  //memoRepository 객체가 자동 생성됨
    
  @Test
    public void testSelect(){
        Long mno = 99L;  // DB에 존재하는 mno  (L은 정수형 타입 long을 의미한다.)
        Optional<Memo> result = memoRepository.findById(mno); 
        => // findById() 는 Optional 타입으로 반환된다.
        System.out.println("===============================");
        if(result.isPresent()){
            Memo memo = result.get();
            System.out.println(memo);
        }
    }

 

*실행결과 - mno가 99인 memo 객체 조회 * 

수정 작업 테스트

  @SpringBootTest
public class MemoRepositoryTests {
    @Autowired // 주입 @Inject가 표준임
    MemoRepository memoRepository;  //memoRepository 객체가 자동 생성됨
    
    @Test
    public void testUpdate(){
        Memo memo = Memo.builder().mno(99L).memoText("Update Text").build();
        System.out.println(memoRepository.save(memo));
    }
 }

JPA는 엔티티 객체들을 메모리상에 보관하려고 하기 때문에
특정한 엔티티 객체가 존재 하는지 확인하는 select가 먼저 실행되고
해당 @Id를 가진 엔티티 객체가 있다면 update, 그렇지 않다면 insert를 실행하게 된다

*실행쿼리 * 

*DB 확인* 

삭제 작업 테스트

  @SpringBootTest
public class MemoRepositoryTests {
    @Autowired // 주입 @Inject가 표준임
    MemoRepository memoRepository;  //memoRepository 객체가 자동 생성됨
    
    @Test
    public void testDelete(){
        Long mno = 99L;
        memoRepository.deleteById(mno);
    }
 }

*실행쿼리 * 

*DB 확인 - mno가 99인 데이터가 삭제됐다.*