본문 바로가기
Java | Spring/Spring 입문

[스프링 입문] 3.5 회원 서비스 테스트

by 동기 2022. 2. 27.
반응형

순서


3.5 회원서비스 테스트

회원서비스 클래스를 테스트 해 보자.

 

1. Test 디렉토리에 Test파일 생성

 

(클래스명 MemberService 에 커서를 두고 단축키를 이용해서 생성할 수도 있다.)

더보기

📌 새로운 테스트 생성 단축키 : command + shift + t (⌘+⇧+t) / 윈도우 : ctrl + shift + t

1. 단축키 클릭 command + shift + t
2. 메소드 선택
디렉토리도 포함해서 자동으로 만들어 진다

 

 

2. 테스트 코드를 만들어 준 뒤 각 메소드별 로직을 작성해 보자. 

📌 given(주어진 것), when(실행) , then(결과) 패턴을 기본으로 진행하면 많음 도움이 된다.

 

2.1 회원가입 작성

📌 테스트 코드는 한글로 해서 알아보기 쉽게 해도 무방하다고 한다 (빌드될때 포함되지 않음)

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

    //when
    Long saveId = memberService.join(member); //join 검증

    //then
    Member findMember = memberService.findOne(saveId).get();
    //assert의 import는 junit이 되기때문에, assertj것을 import하자
    assertThat(member.getName()).isEqualTo(findMember.getName());
}

 

test 정상적으로 수행 완료

 

2.2 중복된 회원에 대해 예외처리하는 로직 작성

📌 저장이 되는것도 중요하지만, 중복회원 검증 로직을 잘 작성하여 예외까지 잘 던지는지 확인해야 한다.

예외를 try catch로 잡을수도 있지만, assertThrows로 해보는것도 좋다.

 

@Test
public void 중복_회원_예외(){
    //given
    Member member1 = new Member();
    member1.setName("spring");
    Member member2 = new Member();
    member2.setName("spring");

    //when
    memberService.join(member1);
    
    //1. try-catch
    
    //2. assertThrows + ramda
    
}

 

option 1. try-catch

try {
    memberService.join(member2);
    fail();
}catch (IllegalStateException e){
    assertThat(e.getMessage()).isEqualTo("exist member");
}

option 2. assertThrows + Ramda

IllegalStateException e = assertThrows(IllegalStateException.class, () -> memberService.join(member2));
assertThat(e.getMessage()).isEqualTo("exist member");

 

 

 

3. 테스트 클래스 전체 실행 해보기

현재 상태로 클래스 전체 테스트를 실행해 보면, 에러가 뜰 것이다.

왜냐? 회원가입()에서 memberService.join을 통해 member 의 이름으로 "spring"을 지정하여 가입(Memory에 생성)이 되어,

 

중복_회원_예약()에 member1 ,2 의 이름으로 "spring"을 지정하고join메서드를 통해 중복체크를 해야하는데, 회원가입()테스트 코드로 이미 같은 이름으로 가입이 되어있어서 중복_회원_예약()에 영향을 끼쳐 해당 메소드를 검증하기도 전에 터져 버린다. ( 반대 순서의 경우도 마찬가지)

 

따라서 각 테스트를 진행한 후에 clear를 해줘야 한다.

Clear코드는 MemoryMemberRepositroy에 작성을 해놨으니, 테스트코드에 추가해준다.

MemoryMemberRepository memberRepository = new MemoryMemberRepository();

 

@AfterEach //동작한 후에
public void afterEach(){ // memory clear
    memberRepository.clearStore();
}

 

각 테스트코드에 동일한 문자열로 이름을 등록하여도, 코드가 동작한 후에 Repository를 clear하기 때문에, 정상적으로 실행이 된다.

 

4. 인스턴스 중복 없애기

MemberService와 , MemberServiceTest의 필드에 생성된 memberRepository는, new 연산자로 생성된 다른 인스턴스이기 때문에, 문제가 될 수 있고 테스트할때는 동일한 Repository를 이용하는것이 좋기 때문에, 같은 인스턴스를 쓰도록 바꿔주는게 좋다. 

MemberService에서 new 연산자로 새로운 memberRepository 객체를 생성하였다.
MemberServiceTest에서도 new 연산자로 새로운 memberRepository 객체를 생성하였다.


(*현재는 임시 DB store로 쓸 Map과, index로 쓸 sequence를 static으로 쓰기 때문에 문제가 없지만, static이 아니라면, 위에 new로 생성한 객체들은 다른 DB이기 때문에 문제가 발생할 수 있다.)


같은 인스턴스를 쓰기위해 아래와 같이 변경해 보자

new 연산자로 인스턴스 생성 -> 생성자 주입(MemberService를 생성할때 외부에서 넣어주도록)

 

1. MemberService 변경

⬇️

MemberService가 생성될때, new 연산자로 새로운 memberRepository 객체 를 생성하지 않고, 외부에서 넣어준 memberRepository를 쓰게 된다.

 

2. MemberServiceTest 변경

⬇️

각 테스트를 실행하기 전에 memberRepository 객체를 생성하고, memberService를 생성할때 넣어준다.

MemberService 입장에서는 직접 new 연산자로 인스턴스 생성을 하지 않고, 외부에서 넣어주는것을 받게되는데, 이것을 의존성 주입, DI(Dependency Injection) 라고 한다

 

이렇게 되면, MemberService 객체와 MemberServiceTest 객체가 동일한 Repository를 쓰게 되는 것이다

기존에는 MemberService 필드에 memberRepository 객체를 new 연산자로 생성하였고,

MemberServiceTest의 필드에도 new 연산자로 memberRepository를 생성하였으나, DI로 인해 동일한 객체 하나로 쓸 수 있다.

 

 

반응형

댓글