이 글은 인프런에서 김영한님의 "스프링 입문 - 코드로 배우는 스프링 부트, 웹 MVC, DB 접근 기술"을 수강 후 개인적으로 공부한 내용을 정리한 게시글입니다. 잘못된 점이나 부족한 부분이 있다면 언제든 지적 부탁드립니다.
- 비즈니스 요구사항 정리
- 회원 도메인과 리포지토리 만들기
- 회원 리포지토리 테스트 케이스 작성
- 회원 서비스 개발
- 회원 서비스 테스트
4. 회원 서비스 개발
: 비즈니스 로직 구현
변수 추출 하기
: ctrl + alt + v
회원가입 + 전체 회원 조회 기능 구현하기
: service 패키지 -> MemberService.java
// result의 값이 있다면
result.ifPresent(m->{
throw new IllegalStateException("이미 존재하는 회원입니다.");
});
memberRepository.findByName(member.getName())
.ifPresent(m->{
throw new IllegalStateException("이미 존재하는 회원입니다.");
});
코드 정리를 해보았음 ! 같은 코드임 !
메소드 뽑기
: ctrl + shift + alt + T
* 리포지토리 함수 이름 (save, findById, findByName) : 단순히 데이터를 DB에 넣다 뺐다 하는 작업 구현
* 서비스 함수 이름 (join, findMembers) : 비즈니스 작업 구현
리포지토리에서 데이터를 DB에 넣고 빼는 직관적인 함수명을 사용했던것과는 다르게
서비스에서는 함수명을 네이밍 할 때 비즈니스 용어 등 비즈니스와 연관되도록 이름을 설계합니다. (예 : join(회원가입을 수행하는 함수))
기획자 <-> 개발자간 원활한 소통을 위해서 서비스 클래스는 비즈니스에 가까운 용어를 쓸 것 !
전체 코드
package hello.hellospring.service;
import hello.hellospring.domain.Member;
import hello.hellospring.repository.MemberRepository;
import hello.hellospring.repository.MemoryMemberRepository;
import java.util.List;
import java.util.Optional;
public class MemberService {
private final MemberRepository memberRepository = new MemoryMemberRepository();
/**
* 회원가입
*/
public Long join(Member member) {
//같은 이름이 있는 중복 회원X
validateDuplicateMember(member); // 중복 회원 검증
memberRepository.save(member); // 검증 통과 시 저장 !!
return member.getId();
}
private void validateDuplicateMember(Member member) {
memberRepository.findByName(member.getName())
.ifPresent(m->{
throw new IllegalStateException("이미 존재하는 회원입니다.");
});
}
/**
* 전체 회원 조회
*/
public List<Member> findMembers() {
return memberRepository.findAll();
}
public Optional<Member> findOne(Long memberId) {
return memberRepository.findById(memberId);
}
}
서비스 로직을 구현하기 위해서도 리포지토리가 필요하다.
MemoryMemberRepository를 memberRepository로 생성한다.
join : 회원가입을 수행하는 함수
회원가입은 중복해서 할 수 없다는 로직을 구현하기 위해 member객체를 validateDuplicateMember로 중복 회원인지 검증 후 리포지토리에 member 객체를 save함수를 이용해 저장하고 생성된 회원의 id를 반환한다
validateDuplicateMember : 리포지토리에 이미 같은 이름으로 등록된 회원이 있는지 확인 후 같은 이름을 가진 회원이 존재한다면 에러메시지를 예외로 날리고 중단하는 함수
findMembers : 전체 회원을 조회
리포지토리의 findAll함수를 사용하여 리스트 형태로 저장소에 등록된 모든 회원 정보를 반환한다
findOne : member의 id를 가지고 특정한 한 회원을 조회
레포지토리 findById 함수를 사용해 반환된 Member객체를 Optional로 감싸 반환해준다
5. 회원 서비스 테스트
: 회원 서비스가 제대로 동작하는지 검증하기 위한 테스트 코드를 작성해보자 !
이전에는 회원 서비스가 메모리 회원 리포지토리를 직접 생성하게 했었다.
-> 위에서 작성한 MemberService에서 Ctrl + Shift + T를 통해 바로 테스트 파일을 생성할 수 있다.
test/java/service 폴더에 MemberServiceTest이름으로 테스트 파일이 생성된다.
# 회원가입()
: 서비스의 join함수의 일반적인 회원가입을 검증하는 테스트
회원가입을 수행하기 위해 Member 객체 member를 생성하고 이름을 hello으로 해준다
memberService의 join을 사용해 member 객체를 넘겨 회원가입을 진행하고 saveId로 회원가입된 객체의 id를 반환받는다
Member 객체(findMember)의 이름과 hello가 동일한지 검증
-> 테스트를 수행하면 error 없이 테스트가 수행되는 것을 확인할 수 있습니다.(테스트 성공)
# 중복 회원 예외처리 확인
:중복_회원_예외() 함수는 중복 회원이 회원가입을 시도할 때 정상적으로 에러 메시지를 출력하는지를 검증하는 테스트
- try catch문
- 방법 2
memberService의 join을 이용해 member1이 회원 가입한다.
assertThrows를 사용하면 특정 로직을 실행 시 그에 해당하는 특정한 예외가 발생하는지를 검증할 수 있다.
이를 사용하여 member1과 같은 이름을 가진 member2가 회원가입을 시도하는 로직을 실행할 때, IllegalStateException의 예외가 발생하는지 검증한다.(단순히 try ~ catch문을 사용하여 확인할 수도 있습니다.)
반환된 예외를 e로 받아 예외 e의 메시지가 터져야 하는 에러의 메시지와 동일한 메시지인지를 확인한다.
테스트를 실행하면 중복회원가입으로 예외가 발생하고, 테스트가 정상 작동함을 확인할 수 있다.
# 메모리 Clear
: MemberRepository 객체 생성 후 -> @AfterEach 사용하기
레포지토리 테스트에서 살펴보았듯이, @AfterEach가 없다면 각 테스트가 실행 후 메모리 DB에 데이터가 쌓이기 때문에 회원가입() 테스트에서 member의 name이 spring이라면 error가 발생할 수 있습니다. 각 테스트 후 메모리 DB에 저장된 데이터를 삭제하기 위해 @AfterEach를 사용해 clearStore으로 리포지토리의 데이터를 지워줘야한다.
.
.
.
그런데!
기존에 우리가 만든 서비스에서도 new로 멤버레포지토리 인스턴스를 만들어준다. 테스트에서도 멤버 레포지토리 인스턴스를 만들어준다. 둘은 엄연히 다른 인스턴스이다.
즉, 각 레포지토리가 다른 인스턴스이기 때문에 내용물이 달리지는 등 문제가 발생할 수 있다.
-> 코드 수정
# MemberService.java
수정된 회원 서비스는 레포지토리를 멤버 변수로 갖고 있고, 멤버 서비스가 생성될 때(테스트 시) 외부에서 레포지토리를 매개변수로 제공받아 멤버 변수인 레포지토리에 넣어준다. 이렇게 수정하면 테스트에 사용되는 레포지토리와 회원 서비스에서 사용하는 레포지토리가 동일한 인스턴스를 사용하게된다.
-> DI(Dependency Injection)가 가능하도록 변경
* Code generation 단축키 (constructor, getter, setter, toString, equals 생성)
: alt + insert
의존성 주입(DI; Dependency Injection)이란 하나의 객체가 다른 객체의 의존성을 제공하는 테크닉을 의미한다. (클라이언트가 어떤 서비스를 사용할 것인지 지정하는 대신, 클라이언트에게 무슨 서비스를 사용할 것인지를 말해주는 것)
# MemberServiceTest.java
테스트 클래스는 회원 서비스와 레포지토리를 멤버 변수로 갖는다.
@BeforeEach는 @AfterEach의 작동방식과 동일하게 각 테스트 실행 전에 호출된다. 이 기능으로 테스트가 각각 수행될 때마다 레포지토리를 생성하고 회원 서비스를 생성 시 생성한 레포지토리를 함께 넘겨준다. 이렇게 생성된 레포지토리를 넘기면서 의존관계를 새로 맺어 각 테스트가 서로 영향이 없도록 할 수 있다.
출처
인프런 김영한님 스프링 입문 강의
'Server > Spring boot' 카테고리의 다른 글
[스프링] 인프런 스프링 입문 #회원 관리 예제 - 웹 MVC 개발 (0) | 2022.01.30 |
---|---|
[스프링] 인프런 스프링 입문 #스프링 빈과 의존관계 (0) | 2022.01.30 |
[스프링] 인프런 스프링 입문 #회원 관리 예제 - 백엔드 개발 #1 (0) | 2022.01.18 |
[스프링] 인프런 스프링 입문 #스프링 웹개발 기초 (0) | 2022.01.18 |
[스프링] 인프런 스프링 입문 #프로젝트 환경설정 (0) | 2022.01.18 |