본문 바로가기
Spring

[Spring] H2, JDBC, JPA / 통합 테스트

by jelliclesu 2024. 9. 11.

스프링 DB 접근 기술

 

H2 데이터베이스 설치

개발이나 테스트 용도로 가볍고 편리한 DB, 웹 화면 제공 [ https://www.h2database.com ]

# 권한 주기
chmod 755 h2.sh

# 실행
./h2.sh

 

데이터베이스 파일 생성방법

  1. JDBC URL: jdbc:h2:~test (최초 한번)
  2. Terminal 에서 home에 test.mv.db 파일 생성 확인
  3. 이후부터 JDBC URL: jdbc:h2:tcp://localhost/~/test

 

더보기

⚠️ H2 데이터베이스 접속 후 주소창에 앞 부부만 localhost 로 변경


순수 JDBC

⚠️ JDBC 로 직접 코딩하는 것은 20년 전 이야기이므로 그냥 이렇게 했었다~정도만 참고하고 넘어가기

 

 

환경 설정

  • build.gradle 에 jdbc, h2 관련 라이브러리 추가
  • application.properties 에 스프링 부트 데이터베이스 연결 설정 추가

 

 

Jdbc 리포지토리 구현 및 설정 변경

  • repository>JdbcMemberRepository.java 생성
  • SpringConfig.java 변경 - MemberRepository 를 JdbcMemberRepository 로 변경

✏️ DataSource: 데이터베이스 커넥션을 획득할 때 사용하는 객체

- 스프링 부트는 데이터베이스 커넥션 정보를 바탕으로 DataSource를 생성하고 스프링 빈으로 만들어둬서 DI를 받을 수 있음

 

 

구현 클래스 추가 이미지

  • 개방-폐쇄 원칙(OCP, Open-Closed Principle):  확장에는 열려있고, 수정, 변경에는 닫혀있음
  • 스프링의 DI 을 사용하면 기존 코드를 전혀 손대지 않고설정만으로 구현 클래스를 변경 가능 (SpringConfig 수정)

 


스프링 JdbcTemplate

환경 설정

  • 순수 Jdbc 와 동일
 

 

스프링 JdbcTemplate 리포지토리 구현 및 설정 변경

  • repository>JdbcTemplateMemberRepository.java 생성
  • SpringConfig.java 변경 - MemberRepository 를 JdbcTemplateMemberRepository 로 변경

‼️ JDBC API 에서 본 반복 코드를 대부분 제거해주지만 SQL 은 직접 작성해야 함


JPA

✔️ 장점

  • 기존의 반복 코드는 물론이고, 기본적인 SQL도 JPA가 직접 만들어서 실행해줌
  • SQL과 데이터 중심의 설계에서 객체 중심의 설계로 패러다임을 전환
  • 개발 생산성 크게 증가

 

 

환경 설정

  • build.gradle 에 JPA 관련 라이브러리 추가 (spring-boot-starter-data-jpa)
  • application.properties 에 JPA 설정 추가 
    ✏️ show-sql: JPA 가 생성하는 SQL 출력
    ✏️ ddl-auto: 테이블을 자동으로 생성하는 기능 - none: 이 기능이 꺼짐 / create: 엔티티 정보를 바탕으로 테이블 직접 생성

 

 

JPA 엔티티 매핑

  • domain>Member.java 수정 - @Entitiy, @Id, @GeneratedValued(strategy = GenerationType.IDENTITY) 추가

 

 

JPA 회원 리포지토리 구현 및 설정 변경

  • repository>JpaMemberRepository.java 생성
  • SpringConfig.java 수정 - MemberRepository 를 JpaMemberRepository 로 변경

✏️ EntityManager: 데이터 소스 등을 내부적으로 처리

- 데이터베이스 커넥션 정보 등을 자동으로 짬뽕해서 스프링 부트가 EntityManager 를 만들어줌

- JPA 를 사용하려면 EntityManager 를 주입받아야 함

 

 

✏️ persist : 영구적으로 저장

✏️ find: 조회

 

 

 

트랜잭션 추가

  • service>MemberService.java 수정 - @Transactional 추가

✏️ @Transactional: 해당 클래스의 메서드를 실행할 때 트랜잭션을 시작

- 메서드가 정상 종료되면 트랜잭션 Commit / 런타임 예외 발생하면 Rollback

- JPA 를 통한 모든 데이터 변경은 트랜잭션 안에서 실행


스프링 데이터 JPA

✔️ 장점

  • 리포지토리에 구현 클래스 없이 인터페이스만으로 개발
  • 기본 CRUD 기능도 스프링 데이터 JPA가 모두 제공 

 

 

스프링 데이터 JPA 제공 기능

  • 인터페이스를 통한 기본적인 CRUD
  • findByName()findByEmail() 처럼 메서드 이름 만으로 조회 기능 제공
  • 페이징 기능 자동 제공

 

 

환경 설정

  • JPA 와 동일

 

 

스프링 데이터 JPA 리포지토리 구현 및 설정 변경

  • repository>SpringDataJpaMemberRepository.java 인터페이스 생성
    package hello.hello_spring.repository;
    
    import hello.hello_spring.domain.Member;
    import org.springframework.data.jpa.repository.JpaRepository;
    
    import java.util.Optional;
    
    public interface SpringDataJpaMemberRepository extends JpaRepository<Member, Long>, MemberRepository {
    
        @Override
        Optional<Member> findByName(String name);
    }
  • SpringConfig.java 수정
    package hello.hello_spring;
    
    import hello.hello_spring.repository.*;
    import hello.hello_spring.service.MemberService;
    import jakarta.persistence.EntityManager;
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.context.annotation.Bean;
    import org.springframework.context.annotation.Configuration;
    
    
    @Configuration
    public class SpringConfig {
    
        private final MemberRepository memberRepository;
    
        public SpringConfig(MemberRepository memberRepository) {
            this.memberRepository = memberRepository;
        }
    
        @Bean
        public MemberService memberService() {
            return new MemberService(memberRepository);
        }
    }

스프링 통합 테스트

  • 단위 테스트: 순수하게 자바 코드로만 최소한의 단위로 테스트
  • 통합 테스트: 스프링 컨테이너와 DB까지 연결된 테스트

‼️ 순수한 단위테스트가 훨씬 좋은 테스트일 확률이 높음 - 스프링 컨테이너 없이 단위 단위 쪼개서 테스트할 수 있도록 훈련 필요

 

 

통합 테스트 생성

  • MemberServiceIntegrationTest.java 생성

✏️ @SpringBootTest: 스프링 컨테이너와 테스트를 함께 실행

✏️ @Transactional: 테스트 케이스에 이 애노테이션이 있으면, 테스트 시작 전에 트랜잭션을 시작하고 테스트 완료 후에 항상 롤백 ➡️ DB에 데이터가 남지 않으므로 다음 테스트에 영향을 주지 않음