회원 기능 테스트

guswls·2023년 2월 5일

JPA 활용 1편

목록 보기
7/9
post-thumbnail

이번 포스팅은 김영한 이사님의 스프링 부트 JPA 활용 1편을 듣고 제작되었습니다.

이번 시간에는 전에 구현한 MemberServiceMemberRespoitory를 토대로 기능이 정상적으로 돌아가는지 테스트를 진행해볼 예정이다.

영상과 달리 포스팅에서는 Junit5라이브러리를 사용할 예정이다.

참고

Junit4의 @RunWith어노테이션은 @ExtendWith로 변경되었다. 하지만 @SpringBootTest를 사용하는 경우 이미 세팅이 되어있기 때문에 @ExtendWith를 사용할 필요가 없다.

1. 회원가입 테스트 구현

@SpringBootTest
@Transactional
class MemberServiceTest {

    @Autowired MemberService memberService;
    @Autowired MemberRepository memberRepository;

    @Test
    void 회원가입() {
        // given
        Member member = new Member();
        member.setName("An");

        // when
        Long savedId = memberService.join(member);

        // then
        assertEquals(member, memberRepository.findOne(savedId));
    }
  • 통합 테스트를 진행하기 위해서는 @SpringBootTest@Transactional 어노테이션이 있어야 된다. 이것에 관한 설명은 스프링 입문 강의 정리에서 다뤘기 때문에 생략한다.
  • membermemberRepository에서 findOne으로 찾은 객체가 같은 이유는 perist가 되는 순간 같은 영속성 컨텍스트에서 관리돼서 같은 것이다.

2. 회원가입 테스트 실행

테스트가 정상적으로 실행된 것을 확인할 수 있다.

신기한 점이 join을 테스트 코드에서 실행했음에도 INSERT문이 발생하지 않은 것을 확인할 수 있다.

값을 저장한 줄 알았는데 INSERT문이 없다?

기본적으로 persist만 하면 INSERT문이 발생하지 않는다. JPA는 기본적으로 트랜잭션이 끝나고 Commit을 해야 INSERT쿼리를 db로 날린다. 하지만 스프링 통합 테스트에서 @Transactional은 디폴트로 트랜잭션이 끝나고 Rollback을 하기 때문에 INSERT쿼리가 날라가지 않는다.
또한, 이것은 우리가 지정한 @GeneratedValue의 타입과도 연관되어 있다. 자세한 정보는 이 글을 참고하자.

만약 db에 쿼리를 날려서 로컬 db에 직접 값이 저장된 것을 확인하고 싶으면 @Commit어노테이션이나 @Rollback(false)로 지정해주면 된다.

만약 INSERT쿼리까지 날리고 Rollback하고 싶으면 flush를 해주면 된다.

@SpringBootTest
@Transactional
class MemberServiceTest {

    @Autowired MemberService memberService;
    @Autowired MemberRepository memberRepository;
    @Autowired EntityManager em;

    @Test
    void 회원가입() {
        // given
        Member member = new Member();
        member.setName("An");

        // when
        Long savedId = memberService.join(member);
        em.flush();

        // then
        assertEquals(member, memberRepository.findOne(savedId));
    }
    		.
            .
            .

INSERT쿼리가 제대로 날라간 것을 확인할 수 있다.

2. 중복 회원 예외 테스트 구현 및 실행

@Test
void 중혹회원_예외() {
    // given
    Member member1 = new Member();
    member1.setName("an");

    Member member2 = new Member();
    member2.setName("an");
    // when
    memberService.join(member1);
    try {
        memberService.join(member2); //예외 발생 확인
    }catch (IllegalStateException e){
        return;
    }
	// then
	fail("예외가 발생해야 합니다.");
}
  • 같은 이름으로 회원 가입을 하였을 때 우리가 만든 validateDuplicateMember가 잘 동작하는지 확인해봐야 한다.
  • fail은 만약 예외가 터지지 않고 동작했을 때 도달하게 되는 영역이며 이 경우는 테스트가 실패하게 된다.

만약 try-catch블록을 주석처리하고 예외를 발생시키지 않는다면 fail에 도달하여 테스트는 실패하게 된다. 하지만 try-catch문을 사용하면 코드가 복잡해지는 경향이 있기 때문에 이를 다른 형태로 구현할 수도 있다.

@Test
void 중혹회원_예외() {
    // given
    Member member1 = new Member();
    member1.setName("an");

    Member member2 = new Member();
    member2.setName("an");
    // when
    memberService.join(member1);

    // then
	assertThrows(IllegalStateException.class, ()->memberService.join(member2));
}
  • Junit5에서는 assertThrows를 통해 예외의 유효성을 판별할 수 있다.
  • assertThat을 사용하여 판별을 하였는데 여기선 assertJassertThat을 사용하였다.
  • assertJ가 아닌 hamcrestassertThat도 있는데 문법이 조금 달라 기호에 맞게 사용하면 된다.
  • 위에 처럼 단순히 유효성만 판별하는 것이 아닌 아래처럼 클래스를 뽑아내거나 에러 메시지를 비교할 수도 있다.
IllegalStateException e = assertThrows(IllegalStateException.class, ()->memberService.join(member2));
//assertThat(e.getClass()).isEqualTo(IllegalStateException.class);
//assertThat(e.getMessage()).isEqualTo("중복된 회원입니다.");

참고

강의에 나오는 @Testexpected옵션은 Junit4에서 Junit5로 넘어오면서 사라지게 되었다. 이번 포스팅을 쓰는 시점에서는 대부분 Junit5를 사용하기 때문에 Junit5를 기준으로 작성을 하였다.

3. H2를 JVM안에서 사용하기

테스트를 할때 외부의 db를 사용하는 것이 아닌 JVM내부의 메모리에서 띄워서 사용하는 방법이 있다.

프로젝트 내부에는 maintest가 완벽히 분리되어 있다. 따라서 resources디렉토리와 그 안의 application.yml을 복붙하면 똑같이 격리된 테스트 환경을 만들 수 있다.

그 다음 H2공식 홈페이지 > cheatSheet로 들어가면 다음과 같은 창이 뜰 것이다.
여기서 yml에서 urljdbc:h2:mem:test 이 주소를 사용하면 된다.

spring:
  datasource:
    url: jdbc:h2:mem:test
    username: sa
    password:
    driver-class-name: org.h2.Driver

이렇게 세팅하고 돌리면 H2 데이터 베이스를 끈 상태에서도 테스트를 돌릴 수 있게 된다.
실제 테스트를 실행하고 Connerction을 살펴보면 우리가 입력한 주소로 잘 연결된 것을 볼 수 있다.

사실 별도의 yml세팅이 없으면 스프링 부트에서 H2 데이터베이스를 메모리에서 실행을 한다. 하지만 이것과 별개로 운영에서의 yml과 테스트에서의 yml은 분리를 해서 사용하는 것이 좋다.

총정리

이렇게 해서 회원 도메인에 대한 테스트가 모두 완료되었다. 테스트를 진행하고 그에 따라 발생하는 쿼리들을 추적해보면서 JPA의 동작 과정에 대해서도 잘 알아볼 수 있었고 특히 PK매핑 방식에 대해서도 별도로 많이 찾아보며 공부할 수 있었다.

또한 강의와 달리 Junit5로 테스트 케이스를 짰었는데 거의 유사하지만 약간의 조금 다른 포인트들이 었어서 찾아보고 구현하며 더욱 머리에 잘 남게 되었다.

점점 알게 되는 것들이 많아지는 것 같아 뿌듯하다.

profile
안녕하세요

0개의 댓글