[스프링 입문] 회원 서비스

atdawn·2024년 5월 9일

SPRING BOOT+JPA

목록 보기
6/49

📹 참고 : 인프런 [ 스프링 입문 - 김영한 ]


서비스 부분을 구현해 보자.
서비스 클래스의 네이밍은 비즈니스에 가까운 용어를 사용한다.

hello/hellospring/service/MemberService.java

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) {
        //같은 이름이 있는지 중복 회원 확인
        validateDuplicateMember(member); //중복 회원 검증
        memberRepository.save(member);
        return member.getId();
    }

        private void validateDuplicateMember(Member member){
            memberRepository.findByName(member.getName()) //이름 조회
                    .ifPresent(m -> { //만약 값이 있으면 실행 (옵셔널이기 때문에 해당 메소드 사용 가능 아니면 if null )
                        throw new IllegalStateException("이미 존재하는 회원입니다."); //예외 발생
                    });
        }


    /**
     * 전체 회원 조회
     */
    public List<Member> findMembers(){
        return memberRepository.findAll();
    }

    /**
     * 회원 아이디 조회
     */
    public Optional<Member> findOne(Long memberId){
        return memberRepository.findById(memberId);
    }
}

회원가입, 전체 회원 조회, 회원 아이디 조회
간단한 세개의 서비스를 구현해보았다.
이번에는 서비스를 테스트 해보자.

테스트 클래스 쉽게 만드는 방법
테스트 하고자 하는 클래스에서 command+shift+T
Create a new Test
JUnit5 선택
멤버 메서드 선택

테스트는 메소드를 한글로 바꾸어도 상관 없다!

🌟Given-When-Then 패턴 [준비-실행-검증]
테스트 코드를 작성시 세 부분을 나누어 작성한다.

  • Given - 테스트에 사용되는 변수, 입력 값을 정의
  • When - 실제 액션을 하는 테스트를 실행
  • Then - 예상한 값, 실제 실행을 통해 나온 값 검증

/src/test/java/hello/hellospring/service/MemberServiceTest.java


class MemberServiceTest {
    MemberService memberService = new MemberService();
    MemoryMemberRepository memberRepository = new MemoryMemberRepository(); //clear()을 사용하기 위해 선언

    @AfterEach
    public void afterEach(){
        memberRepository.clearStore();
    }

    @Test
    void 회원가입() {
        //given
        Member member=new Member();
        member.setName("hello");
        
        //when
        Long saveId= memberService.join(member);
        
        //then 
        Member findMember = memberService.findOne(saveId).get();
        assertThat(member.getName()).isEqualTo(findMember.getName());
    }
    @Test
    void 중복_회원_예외(){
        //given
        Member member1 = new Member();
        member1.setName("spring");

        Member member2 = new Member();
        member2.setName("spring"); //이름 중복

        //when
        memberService.join(member1);
        IllegalStateException e = assertThrows(IllegalStateException.class, () -> memberService.join(member2));
        //제공된 실행 파일의 실행이 예상 유형의 예외를 발생시키는지 확인하고 예외를 반환. member2를 join 했을 때 예외를 기대
        assertThat(e.getMessage()).isEqualTo("이미 존재하는 회원입니다."); //예외 메세지 비교

/*
        try {
            memberService.join(member2);
            fail();
        }catch (IllegalStateException e){
           assertThat(e.getMessage()).isEqualTo("이미 존재하는 회원입니다.");
        }
*/

    }

}

각 메소드마다 정상적인 테스트를 위해서 메모리를 초기화해주는 것을 잊지 말자.

그런데 Test 클래스에서 new MemoryMemberRepository(); 인스턴스와
Service 클래스의 new MemoryMemberRepository(); 는 다른 인스턴스라 static 선언이 없다면 아예 다른 결과를 초래할 수 있다.

그러기 위해서 MemberService 클래스에서 MemoryMemberRepository() 인스턴스를 생성자에 넣어 주어야 한다.

java/hello/hellospring/service/MemberService.java

public class MemberService {
    private final MemberRepository memberRepository;

    public MemberService(MemberRepository memberRepository) {
        this.memberRepository = memberRepository;
    }

...

test/java/hello/hellospring/service/MemberServiceTest.java

class MemberServiceTest {
    MemberService memberService;
    MemoryMemberRepository memberRepository; //clear()을 사용하기 위해 선언

    @BeforeEach //각 메소드 테스트 전 실행
    public void beforeEach(){
        memberRepository = new MemoryMemberRepository(); //clear()을 사용하기 위해 선언
        memberService=new MemberService(memberRepository);
    }

    @AfterEach
    public void afterEach(){
        memberRepository.clearStore();
    }
...

테스트는 독립적으로 실행 되어야 되기 때문에 BeforeEach를 사용한다.
먼저 memberRepositorymemberService변수를 만들고,
beforeEach 메서드 안에서 new MemoryMemberRepository();해준 후 미리 만들어 놓은 변수에 담는다. 그 후 멤버 서비스 또한 미리 만들어 둔 변수에 new MemberService(MemberRepository);를 담는데, 이때 memberRepository를 넣어 생성한다.

이렇게 하면 같은 MemoryMemberRepository가 사용된다.
MemberService 입장에서는 직접 new 하지 않고, 외부에서 MemoryMemberRepository를 넣어준다.
🌟 이것을 Dependency Injection (DI) 라고 한다.

profile
복습 복습 복습

0개의 댓글