스프링 부트와 JPA 활용1 - 회원 도메인 개발 3

JOY·2022년 4월 1일
0
post-thumbnail

📌 스프링 부트와 JPA 활용1 - 회원 도메인 개발 3

인프런 - 스프링 부트와 JPA 활용1 by 김영한 을 기반으로 작성된 글입니다.
실전! 스프링 부트와 JPA 활용1 - 웹 애플리케이션 개발


회원 도메인 개발 목차

1. 회원 리포지토리 개발

2. 회원 서비스 개발

3. 회원 기능 테스트


3. 회원 기능 테스트

  • 회원가입을 성공해야 한다.
  • 회원가입 할 때 같은 이름이 있으면 예외가 발생해야 한다.
MemberService 클래스 Test - 단축키 (Ctrl+ Shift + T for Win/Linux)

1) 회원 기능 테스트 (MemberServiceTest.java)

💻 코드

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 : 테스트 케이스에서 사용 될 때 기본적으로 Rollback

2) 기능

  • 회원 가입 테스트

❓❗ 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가 별도의 설정이 없으면 작성된 코드가 없어도 메모리 모드로 실행된다.

profile
Just Do IT ------- 🏃‍♀️

0개의 댓글