스프링부트 입문 시리즈
#05 회원 서비스 개발 + 테스트 👈
지난 시간에는 회원 리포지토리를 만들어
회원 등록, 회원 검색 기능을 구현해 보고
Test Case를 만들어 테스트까지 모두 마쳤다
이번에 만들 회원 서비스
만들어놓은 회원 도메인과 리포지토리를 활용해서
실제 비즈니스 로직을 구현할 것이다
회원 서비스
클래스 생성
src / main / java / yeon.hello_spring 에서 service 패키지를 만들고
그 안에 MemberService 클래스를 생성한다
회원가입 메소드
회원가입 기능을 구현할 때는 리포지토리에 member를 save 해주기만 하면 된다
public Long join(Member member) {
memberRepository.save(member);
return member.getId();
}
여기에 같은 이름이 있을 경우 중복회원으로 인식해 가입이 안 되는
비즈니스 로직을 하나 추가하려고 한다
Optional<Member> result = memberRepository.findByName(member.getName());
result.ifPresent(m -> {
throw new IllegalStateException("이미 존재하는 회원입니다");
});
memberRepository.findByName(member.getName())으로 리포지토리에 있는 Name을 가져온 다음
result 변수에 담는다. 이때, result는 비어있으면 안 되기 때문에 Optional로 감싸준다
이렇게 감싸진 result는 Optional이 제공하는 ifPresent() 메소드를 사용할 수 있다
ifPresent()를 사용해 값이 존재하는지 확인하고 값이 존재하면 예외처리 한다
위 코드에서는 Optional을 바로 반환했는데, 이렇게 사용하는 방법은 별로 좋지 않다
findByName은 이미 Optional로 감싸져있기 때문에 바로 ifPresent를 사용할 수 있다
다음 코드를 보면 훨씬 간결해지고 가독성이 좋아진 것을 볼 수 있다
memberRepository.findByName(member.getName()).ifPresent(m -> {
throw new IllegalStateException("이미 존재하는 회원입니다");
});
이렇게 작성한 코드는 따로 메소드로 뽑아서 사용하는 것이 좋다
private void memberNameCheck(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);
}
Service는 비즈니스에 의존적으로 설계를 하기 때문에 메소드 네이밍을
Repository보다 좀 더 비즈니스에 가까운 용어를 사용해서 작성하는게 좋다
테스트 해보기
테스트 케이스를 만들면 다음과 같이 껍데기가 만들어진다
class MemberServiceTest {
@Test
void testJoin() {
}
@Test
void testFindMembers() {
}
@Test
void testFindOne() {
}
}
테스트 할 때 MemberService가 필요하기 때문에 MemberService를 하나 만든다
MemberService memberService = new MemberService();
테스트는 어떤 상황이 주어지고 그것을 실행했을때 이런 결과가 나와야 한다인데
이것을 given / when / then 으로 나누어 작성한다
@Test
void testJoin() {
//given
//when
//then
}
회원 가입 테스트
member를 생성하고 setName()으로 값을 넣어준 다음
join()메소드를 통해 리포지토리에 저장한다
findOne().get()으로 리포지토리에 저장된 값을 가져와 findMember에 넣고
getName()으로 가져온 값과 findMember의 값이 같은지를 비교하는 테스트
@Test
void testJoin() {
//given
Member member = new Member();
member.setName("aaa");
//when
Long saveId = memberService.join(member);
//then
Member findMember = memberService.findOne(saveId).get();
assertThat(member.getName()).isEqualTo(findMember.getName());
}
회원 중복 테스트
@Test
void testMemberCheck() {
//given
Member member1 = new Member();
member1.setName("bbb");
Member member2 = new Member();
member2.setName("bbb");
//when
memberService.join(member1);
IllegalStateException e = assertThrows(IllegalStateException.class, () -> memberService.join(member2));
assertThat(e.getMessage()).isEqualTo("이미 존재하는 회원입니다");
}
assertThrows()
assertThrows(에러 class, 에러가 발생해야 하는 로직)
에러 메시지를 비교해 기대하는 에러 메시지와 코드 실행중 발생한 에러가 같으면 테스트가 성공한다
IllegalStateException은 사용자가 값을 제대로 입력했지만, 개발자 코드가 값을 처리할 준비가 안된 경우 발생한다
clearStore()
MemoryMemberRepositoryTest에서와 같이 MemberServiceTest에서도
@AfterEach를 사용해 repository를 비워야 한다
MemoryMemberRepository repository = new MemoryMemberRepository();
@AfterEach
void afterEach() {
repository.clearStore();
}
코드를 자세히 살펴보면
MemberService에 있는 memberRepository와
MemberServiceTest에 있는 repository는
new로 각각 생성된 서로 다른 인스턴스이다
이럴 경우 각각 다른 DB를 사용하고 있는 것과 마찬가이지기 때문에 문제가 생길 수 있다
따라서 다음과 같이 MemberService의 코드를 변경해준다
private final MemberRepository memberRepository;
public MemberService(MemoryMemberRepository repository) {
this.memberRepository = repository;
}
memberRepository를 new로 생성하는 것이 아니라 외부에 넣어주도록 한다
그 다음 MemberServiceTest의 코드를 다음과 같이 변경한다
MemberService memberService;
MemoryMemberRepository repository;
@BeforeEach
public void beforeEach() {
repository = new MemoryMemberRepository();
memberService = new MemberService(repository);
}
이렇게 직접 생성이 아니라 외부에서 넣어주는 것을 의존성 주입(Dependency Injection)이라고 한다
스프링부트 입문 시리즈
#05 회원 서비스 개발 + 테스트 👈
'Framework(Library) > Spring(Springboot)' 카테고리의 다른 글
[스프링부트 입문] 시리즈 #04 회원 리포지토리 만들기 + 테스트 (0) | 2023.09.04 |
---|---|
[스프링부트 입문] 시리즈 #03 회원 관리 페이지 만들기 (0) | 2023.09.01 |
[스프링부트 입문] 시리즈 #02 정적페이지 만들고 화면 띄우기 (0) | 2023.08.31 |
[스프링부트 입문] 시리즈 #01 프로젝트 생성하기 (0) | 2023.08.30 |
[Spring] 빌드 관리 도구 : Maven과 Gradle의 차이 (0) | 2023.08.23 |