반응형
회원 도메인 개발
구현 기능
- 회원 등록
- 회원 목록 조회
순서
- 회원 레포지토리 개발
- 회원 서비스 개발
- 회원 기능 테스트
회원 레포지토리 개발
package jpabook.jpashop.repository;
import jpabook.jpashop.domain.Member;
import org.springframework.stereotype.Repository;
import javax.persistence.EntityManager;
import javax.persistence.PersistenceContext;
import java.util.List;
@Repository
public class MemberRepository {
@PersistenceContext
private EntityManager em;
public void save(Member member) {
em.persist(member);
}
public Member findOne(Long id) {
return em.find(Member.class, id);
}
public List<Member> findAll() {
return em.createQuery("select m from Member m", Member.class)
.getResultList();
}
public List<Member> findByName(String name) {
return em.createQuery("select m from Member m where m.name =:name", Member.class)
.setParameter("name", name).getResultList();
}
}
@PersistenceContext
: 엔티티 매니저 주입@PersistenceUnit
: 엔티티 매니저 팩토리 주입 ( 매니저만 주입받으면 사용가능하므로 해당 애노테이션을 사용하는 경우는 거의 없다.)@Repository
: 스프링 빈으로 등록, JPA 예외를 스프링 기반 예외로 예외 변환createQuery
를 보면 Jpql을 사용했다. 파라미터가 들어가는 경우:
를 사용하고setParameter
로 값을 넣어준다.
회원 서비스 개발
package jpabook.jpashop.service;
import jpabook.jpashop.domain.Member;
import jpabook.jpashop.repository.MemberRepository;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import java.util.List;
@Service
@Transactional(readOnly = true)
@RequiredArgsConstructor
public class MemberService {
private final MemberRepository memberRepository;
/**
* 회원 가입
*/
@Transactional
public Long join(Member member) {
validateDuplicateMember(member); // 중복 회원 검증
memberRepository.save(member);
return member.getId();
}
private void validateDuplicateMember(Member member) {
List<Member> findMembers = memberRepository.findByName(member.getName());
if (!findMembers.isEmpty()) {
throw new IllegalStateException("이미 존재하는 회원입니다.");
}
}
/**
* 전체 회원 조회
*/
public List<Member> findMembers() {
return memberRepository.findAll();
}
public Member findOne(Long memberId) {
return memberRepository.findOne(memberId);
}
}
@Transactional
: 트랜잭션으로 관리하도록 지정 ,readOnly=true
는 변경이 없는 읽기 전용 메서드임을 명시하여, 영속성 컨텍스트에 플러시하지 않게 되어 약간의 성능향상이 발생한다.- 생성자 주입은
@RequiredArgsContructor
를 사용하면 간단하게 표현할 수 있다.
회원 기능 테스트
package jpabook.jpashop.service;
import jpabook.jpashop.domain.Member;
import jpabook.jpashop.repository.MemberRepository;
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.junit.jupiter.api.Assertions.*;
@SpringBootTest
@Transactional
class MemberServiceTest {
private final MemberService memberService;
private final MemberRepository memberRepository;
@Autowired
public MemberServiceTest(MemberService memberService, MemberRepository memberRepository) {
this.memberService = memberService;
this.memberRepository = memberRepository;
}
@Test
public void 회원가입() {
// given
Member member = new Member();
member.setName("sasca");
// when
Long savedId = memberService.join(member);
// then
assertEquals(member, memberRepository.findOne(savedId));
}
@Test
public void 중복_회원_예외() {
// given
Member member1 = new Member();
member1.setName("sasca");
Member member2 = new Member();
member2.setName("sasca");
// when
memberService.join(member1);
// then
assertThrows(IllegalStateException.class, () -> {
memberService.join(member2);
});
}
}
Junit5
기반으로 테스트 코드를 작성했다.- 테스트 시점에서
@Transactional
은 실행할 때마다 트랙잭션으로 만들어서 커밋하고 끝나면 강제로 롤백한다.
메모리 DB 사용법
# test/resources/application.yml 생성
spring:
# datasource:
# url: jdbc:h2:mem:test
# username: sa
# password:
# driver-class-name: org.h2.Driver
# jpa:
# hibernate:
# ddl-auto: create
# properties:
# hibernate:
# show_sql: true
# format_sql: true
logging.level:
org.hibernate.SQL: debug
org.hibernate.type: trace
- 스프링부트는 테스트환경에서
test/resources/application.yml
이 존재하면 테스트단에서 해당 yml을 찾아간다. 이 때,datasource
설정이 없으면 기본적으로메모리 DB
를 사용하고create-drop
모드로 동작한다. 즉, 다음과 같이 주석처리가 되어있어도 자동으로 설정해준다. - 테스트 케이스는 격리된 환경에서 실행하고, 끝나면 데이터를 초기화하는 것이 좋다. 그런면에서 메모리 DB를 사용하는 것이 이상적이다.
본 포스팅은 '인프런 - 김영한님 강의(실전! 스프링 부트와 JPA 활용1)'를 토대로 정리한 내용입니다.
반응형