[Spring-boot]_5차 Service(feat.메모리 저장)

2022. 3. 5. 17:49[SpringBoot]_/[Spring-boot]_인프런 강의

728x90
반응형

4차에 이어서 DB에 저장하는게 아니라 메모리에 저장하고 사용하는 방법에 대한 후속정리 입니다.

https://yn971106.tistory.com/66

 

[Spring-boot]_4차 MemoryRepository(feat.JUnit)

우선 DB를 연동하지 않고 메모리에 저장해서 사용하는 방법을 정리해보았습니다. 1] 사용할 domain, 저장소 개념인 repository 를 만듭니다. 2-1] Member.java 안에 id와 name 이라는 2가지의 데이터필드를 설

yn971106.tistory.com

4차에서 repository에 정상적으로 들어가는지 테스트를 돌려서 확인하였으니 service부분을 만들고 테스트해보겠습니다.

 

1]  service 아래의 MemberService.java

package hello.hellospring.service;

import hello.hellospring.domain.Member;
import hello.hellospring.repository.MemberRepository;
import hello.hellospring.repository.MemoryMemberRepository;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

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


//spring 컨테이너에 서비스를 등록해주는 annotation @Service 입력 가능
public class MemberService {
    //간단하게 테스트 하는법ctrl + shift + t
    
    private final MemberRepository memberRepository;
    
    public MemberService(MemberRepository memberRepository){
        this.memberRepository = memberRepository;
    }
    
    /**
     * 회원가입
     */
    public Long join(Member member) {

        //같은 이름의 중복회원은 안된다. 는 데이터베이스 정의가 있다고 가정
        //ctrl + alt + v
        /*
        Optional<Member> result = memberRepository.findByName(member.getName());
        result.ifPresent(m->{
            throw new IllegalStateException("이미 존재하는 회원입니다.");
        });
        */
        //CTRL + ALT + SHIFT + T = 리펙토리에 관련된 여러가지가 나온다

        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);
    }

}

위의 Repository 에서 작성한 함수 이름과는 다르게, service 파일에서의 함수는 좀더 직관적으로 적습니다.

 

우선 초반의 private final MemberRepository 에서 memberRepository를 가져와서 사용하기 위해서 보통은 new 를 사용해서 가져온다고 생각할 수 있겠지만, 추후 같은 memoryRepository를 바라보게 하기 위해서 생성자로 연결합니다.

 

service는 우선 MemoryRepository = db에 연결하기 위해서 생성자에 MeberRepository를 받아오고 이를 다시 this로 너헝준것입니다.

 

1-1] join 함수

실제로 사용자가 회원가입을 할 때 실행되는 함수로써 여기에 요구사항 들을 설정하게 됩니다.

만약 회원가입시 아이디가 동일하면 가입이 안된다고 할 경우 해당 코드에 메소드를 작성합니다.

 

validateDuplicateMember 함수를 만들어서 판별하게 되고,

해당 함수는 전달받은 member 라는 파라미터에 저장된 이름을 getName을 이용해서 받아오게 되고 이를 findByName이라는 함수에 전달합니다 해당 함수는 그에 맞는 값이 있으면 그값을 리턴하게 됩니다. 이런 함수 뒤에 

ifPresent를 붙임으로써 !=null이 생략되었다고 봐도 됩니다.

 

즉 해당 함수가 실행되서 같은 값이 있으면 무엇인가를 리턴할 것이고 해당 리턴값이 null이 아니라면 동일한 이름이 있기때문에 람다식 함수가 실행되서 throw를 실행시키게 되는 원리입니다.

 

 

2] TEST 코드

해당 service 아래의 MemberService.java를 테스트하는 코드를 빠르게 만들수 있습니다.

window 기준 ctrl + shift + t 버튼을 클릭시 자동으로 만들어줍니다.

자동으로만들어진 java 파일 안에 다음과 같은 코드를 작성합니다.

package hello.hellospring.service;

import hello.hellospring.domain.Member;
import hello.hellospring.repository.MemoryMemberRepository;
import org.assertj.core.api.Assertions;
import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;

import java.util.Optional;

import static org.junit.jupiter.api.Assertions.*;

class MemberServiceTest {

    MemberService memberService;

    MemoryMemberRepository memberRepository;

    @BeforeEach
    public void beforeEach() {
        //같은 memoryRepository를 바라보게 하기 위해서
        //Dependency injection
        memberRepository = new MemoryMemberRepository();
        memberService = new MemberService(memberRepository);
    }

    @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();
        Assertions.assertThat(member.getName()).isEqualTo(findMember.getName());

    }

    @Test
    public 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));

        Assertions.assertThat(e.getMessage()).isEqualTo("이미 존재하는 회원입니다.");


        //then
    }

    @Test
    void findMembers() {
    }

    @Test
    void findOne() {
    }
}

3-1] 코드설명

해당 함수는 

memberService 와 memberRepository를 따로 만들어서 

@BeforeEach 라는 annotation함수안에 생성자로 호출하고 이를 다시 넣어주는데요.

해당 annotation은 after과 반대의 개념입니다. 테스트를 하기전에 같은 repository를 바라보게 하기 위해서 사용하였습니다.

MemoryMemberRepository에 생성자로 만든 memerRepository를 다시 생성자에 전달함으로써 같은 repository를 바라보게 됩니다.

 

또한 test 코드는 실제 프로젝트 제공시 전달이 되는 코드가 아니라서 한국어로 함수를 만들어서 직관적으로 테스트 하여도 무관합니다.

 

test는

given, when , then 이 3가지 큰 틀로 바라보고 작성하는게 좋다고 합니다.

회원가입 함수를 예로 설명해보겠습니다.

해당 함수는 도메인을 받아와서 setName을 통해 해당 member 변수에 hello라는 값을 저장합니다.

그리고 이를 service 딴의 join에 전달하게 되고 이를 saveId 변수에 저장합니다.

이를 service에서 작성한 findOne이라는 함수에 전달하게 되고 이는 전달한 id에 맞는 name을 반환합니다

이를 assertThat을 이용해서 각각을 비교하게 됩니다.

 

감사합니다.

 

https://inf.run/7kwH

 

[무료] 스프링 입문 - 코드로 배우는 스프링 부트, 웹 MVC, DB 접근 기술 - 인프런 | 강의

스프링 입문자가 예제를 만들어가면서 스프링 웹 애플리케이션 개발 전반을 빠르게 학습할 수 있습니다., - 강의 소개 | 인프런...

www.inflearn.com

 

728x90
반응형