CS log

[스프링 입문] 회원 관리 예제 - 회원 서비스 개발, 회원 서비스 테스트 본문

Spring & Spring Boot

[스프링 입문] 회원 관리 예제 - 회원 서비스 개발, 회원 서비스 테스트

sj.cath 2024. 11. 9. 12:11

MemberService를 개발해보려고 한다. service는 비즈니스에 의존적으로(와 관련된 용어를 사용하여) 설계해야한다.

public class MemberService {
    private final MemberRepository memberRepository = new MemoryMemberRepository();

    /*
    회원가입
     */
    public Long join(Member member){
        // 같은 이름이 있는 중복 회원 안됨
        Optional<Member> result = memberRepository.findByName(member.getName());
        result.ifPresent(m -> {
            throw new IllegalStateException("이미 존재하는 회원입니다.");
        });
        memberRepository.save(member);
        return member.getId();
    }
}

 

참고로 아래와 같이 쓸 수도 있다.

public Long join(Member member){
    // 같은 이름이 있는 중복 회원 안됨
    memberRepository.findByName(member.getName())
            .ifPresent(m -> {
        throw new IllegalStateException("이미 존재하는 회원입니다.");
    });
    memberRepository.save(member);
    return member.getId();
}

 

이때 cntrl + T를 해서 extract method 할 수 있다.

public Long join(Member member){
    // 같은 이름이 있는 중복 회원 안됨
    extracted(member);
    memberRepository.save(member);
    return member.getId();
}

private void extracted(Member member) {
    memberRepository.findByName(member.getName())
            .ifPresent(m -> {
        throw new IllegalStateException("이미 존재하는 회원입니다.");
    });
}

 

이후 완성된 코드!

package hello.hello_spring.service;

import hello.hello_spring.domain.Member;
import hello.hello_spring.repository.MemberRepository;
import hello.hello_spring.repository.MemoryMemberRepository;

import java.util.List;
import java.util.Optional;

public class MemberService {
    private final MemberRepository memberRepository = new MemoryMemberRepository();

    /*
    회원가입
     */
    public Long join(Member member){
        // 같은 이름이 있는 중복 회원 안됨
        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);
    }

}

 

이제 memberservice를 테스트해보겠다. memberservice에 ctrl + shift + t 를 하면 아래와 같이 팝업이 뜬다. 그리고 테스트 파일이 자동으로 만들어 진다. test 파일 안에

 

 

테스트는 과감하게 한글로 만들어도 된다. 왜냐하면 직관적으로 쉽게 알아들을 수 있고 실제 작동 코드라고 보지 않기 때문!

이때 추천하는 건 given, when, then 형식이다. 이거에 따라서 하면 좋다.

 +) assertThat 이 잘 안되는 오류가 발생했다. 이 오류는 예전에 개발할 때도 많이 발생했었는데,

import static org.assertj.core.api.Assertions.assertThat;

이렇게 Import를 해주고 test 함수에서는 assertThat 으로 시작하는 함수를 작성해줘야 한다. import 문의 중요성 ,,,😅

테스트 완료!

그래서 then 의 로직을 설명해보자면, 생성된 멤버의 아이디를 받아서 그 멤버의 이름과, 저장된 member들의 이름 중 일치하는 이름이 있는지를 테스트하는 것이다. 이렇게 함으로써 회원가입이 잘 작동하는지 볼 수 있다.

 

그러나 저 코드는 매우 단순하기에 보충해야할 점이 있다. 바로 중복 확인!

 

아래가 MemberService.java 파일 코드의 한 부분인데, "이미 존재하는 회원입니다." 문구와 정확히 일치해야 한다.

public Long join(Member member){
    // 같은 이름이 있는 중복 회원 안됨
    validateDuplicateMember(member);
    memberRepository.save(member);
    return member.getId();
}

private void validateDuplicateMember(Member member) {
    memberRepository.findByName(member.getName())
            .ifPresent(m -> {
        throw new IllegalStateException("이미 존재하는 회원입니다.");
    });
}

 

방법 2

그리고 다른 방법으로도 검증 성공했다. assertthrows는 memberservice에 member2를 넣었을 때 예외가 발생(중복 발생)하면 테스트를 통과한다는 뜻이다. 훨씬 더 가독성이 좋고 간결함을 알 수 있다.

 

아래 코드는 cmd+option+v 키로 변수 e를 받는 방식으로 조금 수정한 거다.

memberService.join(member1);

IllegalStateException e = assertThrows(IllegalStateException.class, () -> memberService.join(member2));// memberservice를 실행했을 때 예외가 발생하면 테스트 통과
assertThat(e.getMessage()).isEqualTo("이미 존재하는 회원입니다.");
더보기

IllegalStateException : 객체가 현재 상태에서 수행할 수 없는 작업을 시도할 때 발생합니다. 즉, 메서드가 호출되기 위한 조건이 충족되지 않았을 때 던져지는 예외

 

NullPointerException : 객체가 null인 상태에서 그 객체의 메서드나 필드에 접근하려고 할 때 발생

 

테스트를 할 때마다 데이터가 clear 되는 코드를 추가해주었는데,

이때 memberservice에서 사용하는 memorymemberrepository와 test에서 생성하는 membermemoryrepository는

서로 다른 객체이다. 현재 Membermemoryrepository에서 회원 저장이 static이지만, 만약 static이 아니게 된다면 ... db 안 내용물이 달라져 문제가 발생할 수 있다. 같은 걸로 테스트하는게 맞는데, 다른 레포지토리로 테스트되는 것이다.

 

생성자 자동생성 : cmd + n

DI : Dependent Injection

즉 memberservice 입장에서 내가 회원 레포지토리를 생성하지 않고 누군가 생성한 걸 넣어주는 로직!