인프런 - 스프링 부트와 JPA 활용1 by 김영한 을 기반으로 작성된 글입니다.
실전! 스프링 부트와 JPA 활용1 - 웹 애플리케이션 개발
package jpabook.jpashop.service;
import jpabook.jpashop.JpashopApplication;
import jpabook.jpashop.domain.Member;
import jpabook.jpashop.repository.MemberRepository;
import org.junit.Assert;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.annotation.Rollback;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringRunner;
import org.springframework.transaction.annotation.Transactional;
import static org.junit.Assert.*;
@RunWith(SpringRunner.class)
@SpringBootTest
@Transactional
public class MemberServiceTest {
/*회원가입 & 중복회원예외 2가지 테스트*/
@Autowired MemberService memberService;
@Autowired MemberRepository memberRepository;
@Test
public void 회원가입() throws Exception {
//given
Member member = new Member();
member.setName("kim");
//when
Long saveId = memberService.join(member);
//then
assertEquals(member, memberRepository.findOne(saveId));
/*각 JPA에서 같은 Transaction 안에서
Id 값(pk값)이 동일하면,
같은 영속성컨텍스트에서 똑같이 관리가 된다.*/
}
@Test(expected = IllegalStateException.class)
public void 중복_회원_예외() throws Exception {
/*MemberService의 validateDuplicatedMember 동작 확인*/
//given
Member member1 = new Member();
member1.setName("kim1");
Member member2 = new Member();
member2.setName("kim1");
//when()
memberService.join(member1);
memberService.join(member2); //예외 발생
//then
fail("예외가 발생해야 한다");
}
}
테스트 케이스 작성
given ( 무언가 주어졌을 때 )
when ( 그것을 실행 하면 )
then ( 이렇게 결과가 나온다 )
1) 기술
@RunWith(SpringRunner.class)
: JUnit 실행시 Spring과 함께 실행@SpringBootTest
: 스프링 컨테이너 안에서 테스트 (없으면 @Autowired 실패)@Transactional
: 테스트 케이스에서 사용 될 때 기본적으로 Rollback2) 기능
❓❗ setName() 을 했는데 쿼리문에 INSERT문이 없다.
MemberService.java - join() 👉 MemberRepository.java - save() 코드 👇
public void save(Member member){
em.persist(member);
}
엔티티매니저 persist()
는 (전략마다 다르긴 하지만)
GenerateValue
전략에서는 기본적으로 INSERT문 생성 안됨
DB Transaction 이 정확히 commit 하는 순간
JPA 영속성 컨텍스트에 있는 멤버 객체가 INSERT문이 만들어지면서 DB 에 INSERT
그런데!
Spring 에 @Transactional
이 테스트케이스에 있으면
기본적으로 Commit 대신 Rollback을 함
🔎 이때 아래 코드를 사용하면 INSERT문 확인 가능
@Rollback(value = false)
H2 DB에 제대로 들어간 것을 확인
@Test(expected = IllegalStateException.class)
사용 하면 try~catch문 작성 안해도 작동
//when()
memberService.join(member1);
try {
memberService.join(member2); //예외 발생
}catch (IllegalStateException e){
return;
}
NullpointerException
회원 가입 테스트 할 때 join() 위치에 오류가 발생했다.
💡 원인
MemberService.java 에서 @RequiredArgsConstructor
를 사용해
final이 있는 필드만 생성자를 생성하도록 했는데 memberRepository 필드에 final이 사라졌다.
이전 실행 할 때 분명히 제대로 동작이 됐었는데 이전 글을 작성할 때
어노테이션을 활용해 생성자 테스트 하면서 final 키워드를 지우고 저장했나보다..
주석은 잘 달아놓고 final 지우고 실행시킨 나 바보
앞으로 잘 확인하자..
💡 해결
다시 final 키워드를 작성해주고 실행하였다. 성공!테스트 케이스는 격리된 환경에서 실행하고, 끝나면 데이터를 초기화 하는 것이 좋다.
❗ 그래서 메모리 DB를 사용하는 것이 가장 이상적 (Springboot에서 쉽게 사용 가능)
테스트 케이스를 실행하면 test 아래에 있는 yml파일이 우선권을 가진다.
url을 라이브러리로 바꾸면 된다
h2.database.com 👉 Cheat Sheet 👉 In-Memory
https://www.h2database.com/html/cheatSheet.html
📂 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-drop
# properties:
# hibernate:
## show_sql: true
# format_sql: true
logging:
level:
org.hibernate.SQL: debug
# org.hibernate.type: trace
실행하면 외부 DB 연결 끊긴다.
❗ Springboot가 별도의 설정이 없으면 작성된 코드가 없어도 메모리 모드로 실행된다.