4. 회원 관리 예제 - 백엔드 개발
4) 회원 서비스 개발
회원 서비스 클래스 생성
- 회원 서비스: 회원 리포지토리 + 도메인 활용해 비즈니스 로직을 작성하는 부분
- (Repository에 비해) 서비스 클래스는 비즈니스에 가깝게 네이밍 해야 함 (∵ 비즈니스 처리하므로)
- Service 패키지 생성 > MemberService 클래스 생성해 작업
1. MemberRepository 객체 생성
- final : 여러 context에서 단 한번만 할당 될 수 있는 entity를 정의할 때 사용
➔ 객체 변수 final : 해당 변수에 다른 참조 값 지정 불가능 (재변경 불가능, 다른 객체로 변경 불가능)
(✔ 객체의 속성(=필드)는 변경 가능)
2. 메서드 정의 - (1)회원 가입 메서드 (join) 정의
- 회원 가입 후 해당 id 반환 (Long) 설정
- 비즈니스 로직 中 같은 이름은 가입이 불가능하다고 설정
- Optional 이기에 ifPresent 가능 (∵ Optional 메서드임) [Optional 안에 맴버객체가 있음]
⇋ Optional이 아니였다면 ifNull() 사용
✔ Null일 가능성이 있는 변수, 객체를 다룰 때는 Optional로 한번 감싸서 사용하자!
(if) Optional에서 맴버 객체를 꺼내 쓰고 싶다? ➤ get메서드 ( ex. result.get() ) [권장X]
✓ 값이 있을 때만 꺼내기 : orElseGet() [권장O]
➔ 별도의 변수 추가 없이 바로 판별해주는 것이 더 깔끔하다. (결과가 Optinal<Member>로 나오는걸 아는 경우)
+
특정 기능을 메서드로 뽑을 수 있는 단축키 (extract Method) : Ctrl + Shift + Alt + T → "7. Extract Method" 선택
중복 회원 검사 기능을 별도의 메서드로 추출해준다.
∴ 회원가입(join) 로직 = (1) 중복 회원 검증 (2) 통과하면 DB에 저장
2. 메서드 정의 - (2) 전체 회원 조회 (findMembers) 메서드, (3) id로 회원 찾기 (findOne) 메서드
3. 검증 하기 - 테스트 케이스 활용 ver.
➔ (5) 회원 서비스 테스트에서 계속...
5) 회원 서비스 테스트
3. 검증 하기 - 테스트 케이스 활용 ver.
✔ 그 전엔 test 하위에 패키지 만들고 직접 작성해줘야 했음
➤ 간단하게 단축키를 이용하자! : 테스트할 클래스에 → Shift + Ctrl + T → Create New Test
➤ 테스트 라이브러리 (JUnit 5), 클래스 네임 자동으로 설정된 테스트 클래스 생성
➤ 테스트할 메서드 선택
➤ test > service 패키지 자동생성> 하위에 MemberServiceTest 생성됨
♘ 테스트용 코드 작성법 : (1) given (2) when (3) then
- given : 검증할 때 사용할 데이터 (비교 당할 데이터)
- when : 검증할 사항 (제대로 작동하는지를 검증할 메서드는 어떤 것?)
- then : 검증 부분 (어떤 방식으로 검증할 것인지?)
3. 검증 하기 - (1) 회원 가입 (join) 메서드
테스트용 메서드명은 한글로 바꿔도 됨! (직관적)
- memberService로부터 찾은 회원을 Optional에서 바로 get으로 꺼내 Member 변수에 저장 (by (ctrl + alt + v))
- static import (alt + enter → Add on -~) 해서 Assertions 생략
✔ 테스트에서는 예외 테스트도 매우 중요하다!!!
➤ join의 핵심은 중복 회원 검증 로직이 잘 작동하는지, 예외 (throw new IllegalStateException) 검증 필수
➤ "중복_회원_예외 메서드"를 추가로 생성해 중복 회원을 저장해보자!
- 같은 name을 가진 member 객체를 각각 member1, member2로 선언한 다음 join을 이용해 Memberservice에 저장
[의도적으로 validateDuplicateMember가 작동해 Exception throw 되게끔 설정]
# 방법 1) try - catch 문으로 검사
...
memberService.join(member1);
try{
memberService.join(member2);
fail("예외 발생 실패"); //Exception이 제대로 발생 안될경우 실행될 코드
}catch (IllegalStateException e){ //성공할 경우 catch 동작
assertThat(e.getMessage()).isEqualTo("이미 존재하는 회원입니다.");
}
# 방법 2) assertThrows 이용
assertThrows("발생할 예외".class, () -> "문제가 될 부분")
얘도 마찬가지로 테스트마다 repository 초기화가 필요하다.
➔ member repository 가져와서 초기화 (after Each 동일하게 생성)
✔ 이전 실행 명령어 다시 실행 = Shift + F10
BUT!!!
memberRepository 객체 (in MemberService 클래스) =/= memberRepository (in MemberServiceTest 클래스)
⇒ 각 객체를 다르게 구분지어 2개로 사용할 필요가 없고, 혹시 모르니 지양하는 것이 낫다.
✘ 문제 상황
MemberService클래스와 해당 테스트 클래스에서 생성되는 MemoryMemberRepository 객체(instance)가 서로 다르다. (⇌ 서로 다른 repository이다) = 테스트해야 하는 것과 다른 repository 테스트
(+!store가 static으로 설정되지 않는다면 문제 발생함 (다른 DB가 되는 것이므로))
✔ 해결 방법
Test에서도 같은 repository를 사용하게 한다.
⇒ MemberService에서 Constructor를 선언 해준다.
(memberRepository를 직접 new로 생성하는 것이 아니라, 외부에서 인자로 넣어주도록 설계한다)
⇒ 테스트 수행 전에 memoryMemberRepository를 생성한 후 MemberService에 인자로 제공하면, 같은 MemoryMemberRepository로 사용됨
⁂ MemberService Class 입장에선 Repository를 직접 new하는 것이 아닌, 외부에서 생성된 memoryMember
Repository를 넣어서 생성 ➤➤➤ Dependency injection (DI: 의존성 주입)
✔ Generate (Constructor 생성) 명령어 = Alt + Insert
✔ 의존성 주입 = 내부에서 만든 변수를 외부에서 넣어주는 것 (의존관계를 외부에서 결정하고 주입)
DI [Dependency Injection]
- DI 종류
- 필드 주입
- setter 주입
- 생성자 주입 (권장) : 의존 관계가 실행중에 동적으로 변하는 경우 거의 없음
'Spring > Spring boot 입문' 카테고리의 다른 글
[스프링 부트] 화면 웹 기능 - 스프링 입문 강의 / 인프런 (0) | 2022.08.19 |
---|---|
[스프링 부트] 스프링 빈과 의존관계 - 스프링 입문 강의 / 인프런 (0) | 2022.08.05 |
[Java] Stream(스트림) 정리 (0) | 2022.07.30 |
[스프링 부트] 회원 관리 예제(1)~(3) - 스프링 입문 강의 / 인프런 (0) | 2022.07.30 |
[스프링 부트] API - 스프링 입문 강의 / 인프런 (0) | 2022.07.27 |