-
#Spring boot-8 회원 기능 테스트SPRING-BOOT 2021. 3. 4. 12:13
[출처] 인프런 김영한 강사님 -실전! 스프링 부트와 JPA 활용1 - 웹 애플리케이션 개발
회원 기능 테스트
테스트 요구사항· 회원가입을 성공해야 한다.
· 회원가입 할 때 같은 이름이 있으면 예외가 발생해야 한다.
회원가입 테스트 코드
package jpabook.jpashop.service; import jpabook.jpashop.domain.Member; import jpabook.jpashop.repository.MemberRepository; 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.context.junit4.SpringRunner; import org.springframework.transaction.annotation.Transactional; import static org.junit.Assert.assertEquals; import static org.junit.Assert.fail; @RunWith(SpringRunner.class) @SpringBootTest @Transactional public class MemberServiceTest { @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)); } @Test(expected = IllegalStateException.class) public void 중복_회원_예외() throws Exception { //Given Member member1 = new Member(); member1.setName("kim"); Member member2 = new Member(); member2.setName("kim"); //When memberService.join(member1); memberService.join(member2); //예외가 발생해야 한다. //Then fail("예외가 발생해야 한다."); } }
기술 설명
· @RunWith(SpringRunner.class) : 스프링과 테스트 통합 (Junit4 실행할때 스프링이랑 같이 엮어서 사용할래)
· @SpringBootTest : 스프링 부트 띄우고 테스트(이게 없으면 @Autowired 다 실패)
· @Transactional : 반복 가능한 테스트 지원, 각각의 테스트를 실행할 때마다 트랜잭션을 시작하고
테스트가 끝나면 트랜잭션을 강제로 롤백 (이 어노테이션이 테스트 케이스에서 사용될 때만 롤백)
기능 설명
· 회원가입 테스트
· 중복 회원 예외처리 테스트
참고: 테스트 케이스 작성 고수 되는 마법: Given, When, Then
(http://martinfowler.com/bliki/GivenWhenThen.html)
이 방법이 필수는 아니지만 이 방법을 기본으로 해서 다양하게 응용하는 것을 권장한다.
테스트시 쿼리를 보고 싶을 경우
1. em.flush()
flush를 사용해 insert되는것만 확인하고 종료시 롤백한다.
@RunWith(SpringRunner.class) @SpringBootTest //이두가지가 있어야 spring이랑 integration 해서 spring boot를 올려서 테스트 할 수 있다. @Transactional public class MemberServiceTest { @Autowired MemberService memberService; @Autowired MemberRepository memberRepository; @Autowired EntityManager em;//query나가는 것을 보고싶을 경우(2) -> flush를 사용해 insert되는것만 확인하고 종료시 롤백한다. @Test public void 회원가입() throws Exception{ //given 이런게 주어졌을때 Member member = new Member(); member.setName("kim"); //when 이렇게하면 Long id = memberService.join(member); //then 이렇게 된다. //query나가는 것을 보고싶을 경우(2) -> em.flush(); //flush함으로써 영속성 컨텍스트에있는 변경 등록 내용을 반영한다. //여기서 저장한 맴버와 repository에서 찾은 애랑 같은 건지 비교한다. //같은 영속성 컨텍스트에서 가지고와서 비교 assertEquals(member,memberRepository.findOne(id)); } }
2. @Rollback(value = false)
디비에 데이터가 쌓인다! 롤백이되지않아서. (test는 반복작업이기 때문에 DB에 데이터가 들어가면 안된다.)
@RunWith(SpringRunner.class) @SpringBootTest //이두가지가 있어야 spring이랑 integration 해서 spring boot를 올려서 테스트 할 수 있다. @Transactional public class MemberServiceTest { @Autowired MemberService memberService; @Autowired MemberRepository memberRepository; @Test @Rollback(value = false) //query나가는 것을 보고싶을 경우(1) -> 디비에 데이터가 쌓인다! 롤백이되지않아서. public void 회원가입() throws Exception{ //given 이런게 주어졌을때 Member member = new Member(); member.setName("kim"); //when 이렇게하면 Long id = memberService.join(member); //then 이렇게 된다. //여기서 저장한 맴버와 repository에서 찾은 애랑 같은 건지 비교한다. //같은 영속성 컨텍스트에서 가지고와서 비교 assertEquals(member,memberRepository.findOne(id)); }
테스트 예외처리
@Test public void 중복_회원_예외() throws Exception{ //given Member member1 = new Member(); member1.setName("kim"); Member member2 = new Member(); member2.setName("kim"); //when memberService.join(member1); try { memberService.join(member2); //예외가 발생해야 한다. }catch (IllegalStateException e){ return; } //then fail("예외가 발생해야 한다."); //여기까지 오면안된다. // 이유-> 이미 위에서 exception이 발생해서 여기까지오면 안되는것 그래서 다시 위에try catch를 걸어줘야한다. }
근데 이렇게 사용하게되면 코드가 지저분하다 이때 사용하는옵션이
@Test(expected = TllegalStateException.class) 이다.
@Test(expected = IllegalStateException.class) public void 중복_회원_예외() throws Exception{ //given Member member1 = new Member(); member1.setName("kim"); Member member2 = new Member(); member2.setName("kim"); //when memberService.join(member1); memberService.join(member2); //예외가 발생해야 한다. //then fail("예외가 발생해야 한다."); //여기까지 오면안된다. // 이유-> 이미 위에서 exception이 발생해서 여기까지오면 안되는것 // 그래서 다시 위에try catch 또는 @Test(expected = IllegalStateException.class)를 해줘야한다. }
이걸 사용하게 되면 예외가 터져나와서 잡힌애가 IllegalStateException이면 알아서 잡아준다.
또한 try catch를 사용하지 않아도 된다.
테스트 케이스를 위한 설정
테스트는 케이스 격리된 환경에서 실행하고, 끝나면 데이터를 초기화하는 것이 좋다.
그런 면에서 메모리 DB를 사용하는 것이 가장 이상적이다.(spring boot에선 공짜로 할 수 있다.)
추가로 테스트 케이스를 위한 스프링 환경과, 일반적으로 애플리케이션을 실행하는 환경은 보통 다르므로 설정 파일을 다르게 사용하자.
다음과 같이 간단하게 테스트용 설정 파일을 추가하면 된다.
1.
test 하위에 resources 폴더 생성 기본적으로 운영로직은 main 하위의 resources가 우선권을 가지고
TEST로직은 test 하위의 resources가 우선권을 가진다.
2.
운영과 똑같은 yml 파일 생성 여기서 url을 메모리로만 바꾸면된다. build.gradle 실제 우리 라이브러리 build.gradle에 h2 DATABASE가 들어가 있다면
얘가 CLIENT 역할만 하는게 아니라 메모리 모드로 DB를 잡아낸다.
H2가 JAVA로 돌기 떄문이다. 그래서 JVM에서 띄울 수가 있다.
아래 주소로들어가
www.h2database.com/html/main.html
H2 Database Engine
H2 Database Engine Welcome to H2, the Java SQL database. The main features of H2 are: Very fast, open source, JDBC API Embedded and server modes; in-memory databases Browser based Console application Small footprint: around 2 MB jar file size Suppor
www.h2database.com
cheat Sheet로 이동 In-Memory의 test를 가지고와서 yml url을 변경한다. url을 jdbc:h2:mem:test 로 변경
실제 db가 꺼져있음에도 test는 잘동작하는 것을 확인 할 수 있다.
그리고 p6spy에서 connection 얻는 url을 보면 jdbc:h2:mem:test 에서 가지고 오는 것을 볼 수 있다.
spring: datasource: # MVCC=TRUE 그나마 여러개가 접근했을때 한번에 처리 넣는것을 권장 #주의: H2 데이터베이스의 MVCC 옵션은 H2 1.4.198 버전부터 제거되었습니다. #1.4.200 버전에서는 MVCC 옵션을 사용하면 오류가 발생합니다. url: jdbc:h2:mem:test username: sa password: driver-class-name: org.h2.Driver # 이렇게까지만 해도 hikariCP를 써서 커넥션 풀이랑 이런게 다 스프링부트가 세팅을 다 걸어줌 jpa: hibernate: ddl-auto: create #자동으로 테이블을 만들어줌. application 실행시점에 내가 가지고 있는 entity정보를 지우고 다시 생성 properties: hibernate: # show_sql: true format_sql: true #이런 속성들은 spring boot 공홈에서 찾아서 공부해야한다. #로그레벨 logging.level: org.hibernate.SQL: debug #jpa나 hibernate가 생성하는 sql로그를 디버그 모드로 쓰겠다. org.hibernate.type: trace
· test/resources/application.yml (spring boot에서는 datasource든 jpa든 다주석 처리해도 돌아간다)
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
이제 테스트에서 스프링을 실행하면 이 위치에 있는 설정 파일을 읽는다.
(만약 이 위치에 없으면 src/resources/application.yml 을 읽는다.)
스프링 부트는 datasource 설정이 없으면, 기본적을 메모리 DB를 사용하고, driver-class도 현재 등록된 라이브러를 보고 찾아준다. 추가로 ddl-auto 도 create-drop 모드로 동작한다. 따라서 데이터소스나, JPA 관련된 별도의 추가 설정을 하지 않아도 된다
그렇기 때문에 여기서도 p6spy에서 connection 얻는 url을 보면 jdbc:h2:mem:test 에서 가지고 오는 것을 볼 수 있다.
참고 : 운영에서 yml과 test의 yml은 항상 별도로 동작하는게 맞기 때문에 따로 설정하자.
test는 그리고 기본적으로 jpa ddl-auto가 create가 아니라 create-drop으로 돌아간다.
(create-drop : 다끝난 다음에 마지막에 drop 완전하게 깨끗이 drop)
'SPRING-BOOT' 카테고리의 다른 글
#Spring boot-9 상품 도메인 개발 (0) 2021.03.04 #Spring boot-8_1 테스트 케이스 작성 중 에러 (0) 2021.03.04 #Spring boot-7_1 TEST CASE 작성 중 발생 에러 (0) 2021.03.04 #Spring boot-7 애플리케이션 구현 준비 (0) 2021.03.03 #Spring boot-6 도메인 분석 설계 (0) 2021.03.01