섹션3의 애플리케이션 구현 준비
이제 섹션 4에선 db랑 소통하는 레퍼지토리 짜고, 서비스 짜고, 이걸 테스트하는 코드를 짜본다.
EntityManager를 저렇게 정의만 해도 lombok이 final 붙은건 가져오기끔 @RequiredArgsConstructor를 한다. 사실 이걸 위해 @Autowired쓰고 아니면 생성자에 붙이고.. 해야 되는데 계속 더 간단한 방법이 나온다.
EntityManger의 createQuery의 특이점은 안의 내용이 결국은 sql문으로 변환되지만 여기선 모델이 아닌 엔터티를 받는다는데 있다.
@Service
@Transactional(readOnly = true) // 읽기 전용이면 성능이 좋아짐
@RequiredArgsConstructor // final이 있는 필드만 가지고 생성자를 만들어줌 (lombok 기능)
public class MemberService {
private final MemberRepository memberRepository;
// @Autowired // 생성자가 하나면 생략 가능
// public MemberService(MemberRepository memberRepository) {
// this.memberRepository = memberRepository;
// }
/**
* 회원 가입
*/
@Transactional
public Long join(Member member) {
// 같은 이름이 있는 중복 회원 X
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);
}
}
여기서 조심할 점은 .save()를 해서 안의 persist를 사용할 텐데 이 줄이 끝난다고 바로 db에 적용되는게 아니다. 저 함수를 호출한 @Transactional 함수가 끝나야 적용된다.
@RunWith(SpringRunner.class)
@SpringBootTest
@Transactional
class MemberServiceTest {
@Autowired
MemberService memberService;
@Autowired
MemberRepository memberRepository;
@Autowired
EntityManager em;
@Test
public void 회원가입() throws Exception {
// given
Member member = new Member();
member.setName("kim");
// when
Long savedId = memberService.join(member);
// then
em.flush(); // DB에 쿼리를 날림. 그래도 어차피 @Transactional 때문에 끝나면 롤백됨.
assertEquals(member, memberRepository.findOne(savedId));
}
@Test
public void 중복_회원_예외() throws Exception {
// given
Member member1 = new Member();
member1.setName("kim");
Member member2 = new Member();
member2.setName("kim");
// when
memberService.join(member1);
Assertions.assertThrows(IllegalStateException.class, () -> memberService.join(member2));
// 예외가 발생해야 한다.
// then
}
}
실제 db를 사용하는것이 아닌 인메모리 테스트를 위해, 즉 실제 product 실행 환경과 테스트 환경 db를 분리하기 위해 test쪽에도 application 설정 파일을 만들어준다. 원래 h2:mem:test와 같이 메모리에서 돌린다는걸 명시해야 하지만 테스트 환경에선 메모리 테스트가 기본값이기 때문에 생략해도 된다.
'CS > 김영한 스프링 강의' 카테고리의 다른 글
실전! 스프링 부트와 JPA 활용1 - 웹 애플리케이션 개발 - 섹션6. 주문 도메인 개발 (1) | 2023.09.11 |
---|---|
실전! 스프링 부트와 JPA 활용1 - 웹 애플리케이션 개발 - 섹션5. 상품 도메인 개발 (0) | 2023.09.09 |
실전! 스프링 부트와 JPA 활용1 - 웹 애플리케이션 개발 - 섹션2. 도메인 분석 설계 (0) | 2023.09.07 |
실전! 스프링 부트와 JPA 활용1 - 웹 애플리케이션 개발 - 섹션1. 프로젝트 환경설정 (0) | 2023.09.03 |
스프링 DB 2편 - 데이터 접근 핵심 원리 - 섹션11. 스프링 트랜잭션 전파2 - 활용 (0) | 2023.09.02 |