이번에는 Servie 계층을 구현하려고 합니다.

우리 화면에서 이메일과, Role 을 헤더 부분에 보여주려고 합니다.
앞에서 레포지토리 계층을 개발했던 것처럼 이번에도 서비스 계층에 대한 테스트 클래스부터 작성해 주면 됩니다..
서비스 테스트 만들기

맥북 기준 cmd + shift + t 입니다.
근데 원래는 서비스 클래스를 만드는것보다 서비스 테스트코드를 먼저 짜야하기 때문에 순서가 바뀌었지만.
클래스명만 만들고 만드는것도 나쁘지 않은거 같습니다. 왜냐하면 폴더 위치까지 다 알아서 만들어 주기 때문이죠
서비스 계층은 데이터 베이스에 데이터를 처리하는 Repo 계층을 모킹하기 위해 MockitoExtension 에서 실행 되도록 합니달.
Mockito 도 테스팅 프로임 워크이기 떄문에 JUnit 과 결합되기 위해서는 별도의 작업 이 필요한대 그것이 바로
@ExtendWith(MockitoExtension.class)
이거를 사용해주면 됩니다
그러면 예를들어 컨트롤단에서는 서비스단이 주입이 된다거나, 서비스단에서는 레포가 주입이 됩니다.
memberService 는 테스트 대상이므로 의존성이 주입되는 어노테이션인 @InjectMocks를 붙여주고, MemberRepository 가 의존성이 있는 클래스 이므로 가짜 객체 생성을 도와주는 @Mock을 붙여줍니다
@ExtendWith(MockitoExtension.class)
class MemberServiceTest {
@InjectMocks
private MemberService memberService;
@Mock
private MemberRepository memberRepository;
}
이제 멤버의 email과 role을 가져오는 코드를 작성하면 되는데, 실패하는 테스트 코드 들을 먼저 작성 합니다.
1. 내 정보를 가져오기 전에 해당 멤버가 존재하는지 여부 체크한다.
@ExtendWith(MockitoExtension.class)
public class MemberServiceTest {
@InjectMocks
private MemberService memberService;
@Mock
private MemberRepository memberRepository;
@Test
@DisplayName("getMember: ErrorCase1. 해당 멤버를 찾지 못할 때")
void test1(){
// given
doReturn(Optional.empty()).when(memberRepository).findByEmail(any(String.class));
// when
IllegalArgumentException ex = assertThrows(IllegalArgumentException.class, () -> memberService.getMyEmailAndRole("test@test.com"));
//then
assertThat(ex.getMessage()).isEqualTo("Account cannot be found");
}
public Member getMember(){
return Member.builder()
.email("test@test.com")
.role(Role.GOLD)
.build();
}
}
doreturn을 사용하게 되면
findbyemail 을 해서 아무 스트링값을 넣으면 enpty값을 반환 해준다는 것입니다.
이렇게 되면 해당하는 계정이 없어 테스트는 통과하게 된다. 다음으로는 해당 멤버를 찾았을때 테스트 코드를 작성해줍니다.
@Test
@DisplayName("getMyEmailAndRole(): Success")
void test2() {
// given
Member mockMember = getMember(); // 동일 객체 사용
doReturn(Optional.of(mockMember)).when(memberRepository).findByEmail(any(String.class));
doReturn(new LoginDataResDto("test@test.com", "GOLD"))
.when(typeChange).MemberToMyEmailAndRoleDto(mockMember); // 동등성 비교
// when
LoginDataResDto result = memberService.getMyEmailAndRole("test@test.com");
// then
assertThat(result.email()).isNotNull();
assertThat(result.role()).isEqualTo(Role.GOLD.name());
// verify
verify(memberRepository, times(1)).findByEmail("test@test.com");
verify(typeChange, times(1)).MemberToMyEmailAndRoleDto(mockMember);
}
TypeChange 라는 클래스가 따로 필요하기 때문에 그것또한 @Mock 으로 해줍니다..
doReturn(...).when(...)
- doReturn(returnValue):
- 메서드 호출 시 반환될 값을 정의합니다.
- 여기서 returnValue는 해당 메서드가 호출되었을 때 반환될 값입니다.
- 이 방식은 일반적으로 when(...).thenReturn(...)과 같은 역할을 합니다
- .when(mockObject):
- Mock 객체를 지정합니다.
- 여기서 지정된 Mock 객체의 특정 메서드가 호출될 때 반환 동작을 정의합니다.
- .methodCall(arguments):
- Mock 객체에서 호출할 메서드와 해당 메서드에 전달되는 매개변수를 지정합니다.
즉 지금 상황해서는 findbyemail 에 아무 string 값 넣으면 mockMember를 주고 membertoMyEmailAndRole 했을대 LoginDataResDto를 만들어 주는것입니다.
예전에 한 번 잠깐 배웠을때 때 AssertThat 까지는 봤는데요 이번에 verify 는 처음 봅니다.
Verify는 결과가 아니라 조작한 동작을 확인하고 싶은 경우 이용하는것입니다. 즉 몇번 호출했는지 알 수 있다고 보면 됩니다.
안에는
- times(n) : n번 실행 여부
- never() : 실행 안되어야함.
- atMostOnce() : 최대 1번 실행
- atLeastOnce() : 최소 1번 실행
- atLest(n) : 최소 n번 실행
- atMost(n) 최대 n번 실행
이런것들이 있다고 합니다.
이렇게 테스트 코드를 작성하고 나서 실제 서비스 단은
public LoginDataResDto getMyEmailAndRole(String email) {
Member member = memberRepository.findByEmail(email).orElseThrow(
() -> new IllegalArgumentException("Account cannot be found"));
return typeChange.MemberToMyEmailAndRoleDto(member);
}
일단 다음과 같이 작성하게 됩니다.
다음에는 Controller 계층으로 돌아오겠습니다.
댓글