반응형

이번 시간에는 회원 서비스 클래스를 테스트 해볼 것이다.

이전시간에 테스트를 할 때는,

이렇게 패키지를 만들어서 직접 했는데,

엄청 편하게 하는 방법이 있다.

 

테스트 하고싶은 클래스에 커서를 두고 , cmd+shift+t 를 누르면

Creat New Test를 누를 수 있다.

 

테스팅 라이브러리는 Junit5를 선택하고,
클래스 이름은 MemberServiceTest라고 지정한다.
그리고 테스트할 메서드를 선택체크 해주면 된다.

OK를 누르면, 이렇게 자동으로 테스트 껍데기를 만들어 준다.


생성된 위치는 test폴더에 service패키지에 만들어졌다.

이제 하나씩 작성해보자.

테스트 코드를 제외한 실제 동작하는 코드들은, 한글로 네이밍하는 것이 관례적으로 금기되었는데,
테스트 코드는 영어권 사람들과 일하는게 아니라면, 한글로 네이밍하기도 한다.
많은 사람들이 좀더 직관적으로 쉽게 알아들을 수 있기 때문이다.
그리고 해당 프로젝트가 빌드될 때, 테스트 코드는 포함되지 않기때문에 더욱이 그렇다.

 

회원가입을 하려면 우선, 서비스가 있어야 한다.

 

테스트는 사실, 생각해보면,


1. 뭔가가 주어졌는데,
2. 이것이 실행되었을 때,
3. 결과가 이게 나와야해!

대부분 이러한 과정으로 진행된다.

그래서 given, when, then 으로 나눠서 작성하면 좋다.

그래서 given을 보면, "아! 이 데이터를 기반으로 하는구나!"
when을 보면, "아 이걸 실행하는걸 검증하는구나!
then을 보면, "여기가 이제 검증부구나!"
라는 것을 알 수 있다.

그래서 이렇게 주석을 작성해 두는 것만으로도 많은 도움이 된다.
물론 상황에 따라 다양하게 변형해야 하겟지만, 기본틀은 이러하다는 것을 알아두자.

회원가입 테스트코드를 작성했다.

테스트를 통과했다.

그런데 여기서 중요한점이 있다.

위에 작성한 회원가입 테스트 코드는 너무 단순한 동작이다.

테스트는, 정상범주의 케이스도 중요하지만, 예외 범주의 케이스가 더 중요하다.

join을 살펴보면 알 수 있듯,
저장이 되는 것도 중요하지만, 더 중요한 것은,
중복 회원을 검증해서 중복회원이 존재하면, 중복검징 로직을 잘 타서 예외를 발생시키는 것이 중요하다.

중복_회원_예외라는 이름으로 테스트를 작성해보자.

예외가 발생했을 때, 주어지는 메시지가 Service클래스의 validateDuplicateMember 에서 예외를 던질 때 주는 메시지와 같은지 비교하도록 했다.

테스트에 통과했다.

이번에는 임의로 메시지를 변경해보자. 그러면 실패해야 한다.

테스트에 실패함을 확인할 수 있다.

 

위의 코드처럼 작성하는 방법이 있지만,
그런데, 이러한 예외테스트 때문에 try-catch문을 넣는게 조금 비효율적(?)으로 애매하다.

그래서 좋은 문법이 제공된다. 한번 알아보자.

우선 앞서 작성해둔 try-catch문은 주석처리 했다.

 

assertThorws 라는 문법인데,
"중복회원 예외가 발생했을 때, IllegalStateException.class가 발생해야 해!" 라고 알려주고,
람다가 넘어가서
어떤로직을 태울때 IllegalStateException.class가 발생해야 하는지 알려준다.
memberService.join(member2)); 를 넣으면, 예외가 터져야 한다고 알려주는 것이다.

즉, memberService.join(member2)); 를 넣으면 IllegalStateException.class 예외가 터져야 한다고 알려주는 것이다.

테스트를 돌려보자.

테스트에 통과했다.

만약에 터져야 하는 예외가 IllegalStateException가 아니라 NullPointerException 이 터져야 한다고 임의로 지정하고 테스트를 돌리면?

테스트에 실패하는 것을 확인할 수 있다. 다시 원래대로 IllegalStateException로 작성해두자.

assertThrows의 또다른 좋은점은 메시지도 반환 할 수 있다는 것이다.

이렇게 작성하고, 테스트를 돌려보면,

테스트에 성공하는 것을 확인할 수 있다.

 

자 이제, 테스트 코드를 작성할 때 꼭 해줘야 하는게 남아있다.

앞서 이야기 했듯,

모든 테스트는 순서와 상관없이 다 메서드별로 따로 동작하도록 설계해야한다.
절대로 순서를 의존적으로 설계하면 안된다.

즉, 메서드를 실행하고나면 데이터를 깔끔하게 클리어 해줘야 한다.
 
그런데, 지금 MemberServiceTest클래스 코드에 문제가 있다.
데이터를 클리어해주고 싶은데, MemberServiceTest클래스의 멤버가 MemberService밖에 없다.

클리어가 안될 것이다.

그래서 어떻게 하냐면,
MemoryMemberRepository를 가져와야 한다.

 

 

이렇게 해두면, 메서드가 돌때마다, db의 값을 clear해준다.

테스트에 성공하는 것을 볼 수 있다.

돌때마다 메모리가 클리어가 되서 잘 동작한다.

 

 

그런데, 이 코드를 보자. 조금 애매한 부분이 있다.

 

MembeService 클래스에 있는 memberRepository는 new연산자를 이용했기 때문에, 다른 객체이다.

MemberServiceTest클래스에 있는 memberRepository와 다른 객체이다.

애매해다고 말한이유가 바로 이것이다.
이렇게 따로 2개를 쓸 이유가 없다. 같은 것을 사용하는게 아무래도 낫다.

이렇게 new로 다른 객체가 생성이 되면, 서로 다른 인스턴스 이기 때문에 혹시라도 내용물이 달라지거나 그럴수 있다.

그래서 어떻게 하는것이 좋냐면, 같은 인스턴스를 사용하도록 코드를 수정하는게 좋다.

 

MemberService 클래스의  new MemoryMemberRepository() 를 지우고,
new로 직접 생성하는 것이 아니라 외부에서 넣어주도록 바꿔줘야 한다.

cmd+n을 눌러서 Constructor를 눌러준다.

 

그러면, MemberService의 MemberRepository memberRepository를 직접 new해서 생성하는게 아니라,
외부에서 넣어주도록 변경된다.

 

그러면, MemberServiceTest클래스에서 MemberService()를 생성할 때,  내가 MemoryMemberRepository를 직접 넣어줄 수 있다.

어떻게 하냐면,

@BeforeEach로 동작하기 전에 넣어주면 된다.

이것이 동작하는 방식은,

각 테스트를 실행하기 전에, @BeforeEach가 실행되는데,

MemoryMemberRepository() 가 만들어진다.

그리고, 만들어진 memberRepository를 MemberServiceTest클래스의 memberRepository에 넣어 놓는다.

new MemberService(memberRepository);를 할 때,

MemberService클래스에서 만들어둔 memberRepository를 넣어준다.

그러면, 같은 MemoryMemberRepository를 사용하게 된다.

 

이것을 뭐라고 하냐면,

MemberService 입장에서 자신이 직접 new하지 않고 외부에서 MemberRepository를 넣어준다.

이러한 것을 Dependency Injection(DI 의존성 주입) 이라고 한다.

이것과 관련된 자세한 내용은 다음시간에 좀더 알아보도록 하겠다.

 

반응형