It's easy, if you try

[SpringBoot] 스프링부트와 JPA 활용 섹션 3, 4 - 어플리케이션 아키텍처/ 개발순서 / 엔티티, 리포지토리, 서비스, 테스트 작성 본문

스프링

[SpringBoot] 스프링부트와 JPA 활용 섹션 3, 4 - 어플리케이션 아키텍처/ 개발순서 / 엔티티, 리포지토리, 서비스, 테스트 작성

s5he2 2023. 2. 19. 20:00
반응형

1) 어플리케이션 아키텍처

계층형 구조 사용

  • controller, web: 웹 계층 (컨트롤러는 repository에 접근가능, 단방향)
  • service: 비즈니스 로직, 트랜잭션 처리
  • repository: JPA를 직접 사용, 엔티티 매니저 사용
  • domain: 엔티티가 모여있는 계층, 모든 계층에서 사용

패키지 구조

  • domain
  • exception
  • repository
  • service
  • web

개발순서

  1. 서비스, 리포지토리 계층 개발
  2. 테스트 케이스 작성
  3. 웹계층 적용
  • 도메인 개발
  • 웹계층 개발
    • 타임리프로 화면 개발
    • 화면과 기능 연결
  • API 개발
    • ajax 통신 , 안드로이드같은 네이티브 통신시에도 필요 

2) 엔티티 클래스 개발

참고:  (https://sohee-dev.tistory.com/152)

  • 객체지향적인 측면에서 핵심 비즈니스로직을 작성한다.
    • ex> item 엔티티가 stockQuantity(수량) 속성을 가질 때, 수량증가(addStock) - 이는 데이터를 가지고 있는 곳에서 비즈니스 메소드를 작성한 것. 
    • setter를 통해 외부에서 변경하는 것이 아니기 떄문에 변경 포인트를 명시해둘 수 있고, 관리가 용이하다.

3) 리포지토리 개발

DB에 직접 접근

  • @Repository : 스프링컨테이너에 리포지토리를 스프링 빈으로 등록
  • @PersistenceContext , EntityManager:
    javax.persistence.*;
    스프링이 엔티티매니저를 생성하여 주입해준다.
    • @RequiredArgsConstructor + final 필드 EntityManager 로 대체 가능 (일관성 있는 코드 작성에 유용)
  • em.createQuery("JPQL문법", 반환형식);
    sql은 테이블을 기준으로, JPQL은 엔티티를 기준으로 쿼리 작성

4) 서비스 개발

  • @Service
  • @Transactional : 데이터 변경 로직이 있다면 꼭 명시해야함
    • javax와 springframework (권장)에서 제공
    • @Transactional(readOnly = true): 조회할때 성능 최적화
      class에 readOnly=true 옵션을 주고, 쓰기 기능을 하는 함수 위에 @Transactional (readOnly=false (default임))을 명시해도됨.
  • @Autowired
    • 필드 인잭션 : 간편하지만, 테스트 시에 불편함 (변경 불가능), 변경 불가능 명시를 위해 final  (그림 1)
    • setter 인잭션 : 변경이 가능하다, 변경이 가능해서 오히려 위험 (그림 2)
    • 생성자 인잭션 : 중간에 변경 불가능, 테스트시에도 좋음 (그림 3)
      • @RequiredArgsConstructor : 롬복 문법으로, final이 있는 필드에 대해서 생성자를 만들어줌.
      • @NoArgsConstructor: 기본 생성자만 생성
      • @AllArgsConstructor: 전체 변수를 생성하는 생성자를 만들어준다.
        • 옵션 access = AccessLevel.PROTECTED : 외부에서 set 할 수 없도록 하는 옵션
  • 중복 검증 등의 로직 추가 (EXCEPTION)
    throw new IllegalStateException("이미 존재하는 회원입니다.");
    멀티스레드의 환경을 고려(동시접근)하여, 테이블에 유니크 조건 제약을 두는 등 한번더 검증하기.

그림1 (필드 인잭션)
그림2 (세터 인잭션)
그림3 (생성자 인잭션)

5) 기능 테스트

1) 테스트 요구사항 파악

2) 테스트 코드 작성

  • command + shift + T : 테스트 클래스 생성 (JUnit4)
  • class에 명시
    • @SpringBootTest
    • @Transactional
    • @RunWith(SpringRunner.class)
  • 테스트 함수 위에 명시
    • @Test
      • @Test(expected = IllegalStateException.class) : 예외가 발생하면 테스트 성공
  • fail("실패 메시지");

4-1) 메모리 DB 사용하기 

테스트는 케이스 격리된 환경에서 실행하고, 끝나면 데이터를 초기화하는 것이 좋다. 그런 면에서 메모리 DB를 사용하는 것이 가장 이상적이다. 추가로 테스트 케이스를 위한 스프링 환경과, 일반적으로 애플리케이션을 실행하는 환경은 보통 다르므로 설정 파일을 다르게 사용하자. 다음과 같이 간단하게 테스트용 설정 파일을 추가하면 된다.

테스트 폴더 안에 application.yml 파일을 복사 붙여넣기해서 사용하면 이위치 파일을 먼저 참조한다.

spring:
#  datasource:
#    url: jdbc:h2:mem:testdb
#    username: sa
#    password:
#    driver-class-name: org.h2.Driver
#  jpa:
#    hibernate:
#      ddl-auto: create
#    properties:
#  hibernate:
#        show_sql: true
#    format_sql: true
#open-in-view: false

logging.level:
org.hibernate.SQL: debug
#  org.hibernate.type: trace
스프링 부트는 datasource 설정이 없으면, 기본적으로 메모리 DB를 사용하고, driver-class도 현재 등록된 라이브러리를 보고 찾아준다. 추가로 ddl-auto 도 create-drop 모드로 동작한다. 따라서 데이터소스나, JPA 관련된 별도의 추가 설정을 하지 않아도 된다.
  • create-drop 모드 : 어플리케이션이 종료될때 table을 drop
반응형
Comments