본문 바로가기
백엔드/스프링

비즈니스 예제

by dustnn 2025. 5. 12.

[[/비즈니스 요구사항 정리]]
[[
/회원 도메인과 리포지토리 만들기]]

[[/회원 리포지토리 테스트 케이스 작성]]

[[/회원 서비스 개발]]
[[
/회원 서비스 테스트]]

 

비즈니스 요구사항 정리

 

- 데이터: 회원ID, 이름
- 기능
: 회원 등록, 조회
- 아직 데이터 저장소가 선정되지 않음
(가상의 시나리오): nosql 등 데베 종류가 아직 선정 x

 

일반적인 웹 애플리케이션의 계층 구조

 

 

- 컨트롤러: 웹 MVC의 컨트롤러 역할

- 서비스: 핵심 비즈니스 로직 구현

- 리포지토리: 데이터베이스에 접근, 도메인 객체를 DB에 저장하고 관리

- 도메인: 비즈니스 도메인 객체

ex. 회원, 주문, 쿠폰 등등 주로 데베에 저장 및 관리

 

클래스 의존 관계

 

- 아직 데이터가 선정되지 않았기 때문에, 우선 인터페이스를 두어 구현 클래스를 추후에 변경할 수 있도록 설계

- 데이터 저장소는 RDB, NoSQL 등 다양한 저장소를 고민중이며

- 초기 개발 단계에서는 구현체로 가벼운 메모리 기반의 데이터 저장소 사용

 

코드

 

<회원 객체를 저장하는 repository 만들어 저장>

 

인터페이스 <MemberRepository>

 

- 회원 이름 저장

- 회원 조회

 

구현체 <MemoryMemberRepository>

 

1. 

 

2. 메소드 오버라이딩

 

 

회원 도메인과 리포지토리 만들기

 

 

MemoryMemberRepositoryTest 에서 테스트하는 코드들을 살펴볼 것이다.

"@Test"

- save()

- findByName()

- findAll()

save()

 

그냥 다음과 같이 적어줘도 실행되지만

 

반환 타입이 optional이기 때문에 get()

Assertions.assertEquals(member, result);
//assertThat(member).isEqualTo(result);

 

위 두 코드는 같은지 확인해주는 같은 코드이므로 대체 가능

findByName()

 

findAll()

 

객체 2개이므로 isEqualTo(2)
3을 넣으면 에러

 

하지만 한꺼번에 돌리면 에러가 난다. findAll() 에서 이미 spring1, spring2 라는 객체가 생성되었지만 ..

findByName()에서도 생성을 원하므로 중복이 발생한 것이다.

 

따라서 각 함수가 실행된 이후 다른 함수가 실행되기 전에 지워주는 함수를 따로 두어야 한다.

 

-> @afterEach

 

우선 repository에 clear해주는 함수를 써주고

 

객체를 만들어 clear해준다. 그러면 이제 함수의 실행 순서와 관련 없이 에러가 나지 않는다.

 

 

돌려야 하는 테스트가 수십 수백개라면 다음과 같이 하면 된다. 그럼 자동으로 다 돌려준다.

회원 서비스 개발

서비스를 만들기 위해서는 repository가 있어야 함

 

<MemberService>

package hello.hellospring.service;

import hello.hellospring.domain.Member;
import hello.hellospring.repository.MemberRepository;
import hello.hellospring.repository.MemoryMemberREpository;

public class MemberService{
	private final MemberRepository memberRepository = new MemoryMemberRepository();
    
    /**
 	*회원가입
    */
    public Long join(Member member){
    	//같은 이름이 있는 중복 회원 x
        //memberRepository.findByName(member.getName()); -> 단축키 "command+option+v" 하면 아래와 같이 Optional로 감싸짐
        Optional<Member> result = memberRepository.findByName(member.getName()); // member를 optional로 감싸기 -> optional 안의 여러 메소드 사용 가능(ifPresent 등)
        result.ifPresent(m -> { // m에 값이 있으면 실행
        	throw new IllegalStateException("이미 존재하는 회원입니다.");
        })
        //다음과 같이 해도 됨
        //memberRepository.findByName(member.getName()).ifPresent(m -> {
        //	throw new IllegalStateException("이미 존재하는 회원입니다.");
        //}
        //하지만 너무 치렁치렁이므로 "command+option+m" 눌러서 메소드로 빼주기 가능
    	memberRepository.save(member);
        return member.getId();
    }
    /**
    *전체 회원 조회
    */
    public List<Member> findMembers() {
    	return memberRepository.findAll();
    }
    
    public Optional<Member> findOne(Long memberId){
    	return memberRepository.findById(memberId);
    }
}

 

회원 서비스 테스트

 

class에서 "command+shif+T" 누르면 test 페이지가 자동으로 만들어진다.

 

package hello.hellospring.service;

import hello.hellospring.domain.Member;
import org.junit.jupiter.api.Test;

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

class MemverServiceTest {
	MemberService memberService = new MemberService();
    MemoryMemberRepository memberRepository = new MemoryMemberRepository();
    
    @AfterEach //함수 실행 끝나면 메모리 clear -> 에러 방지
    public void afterEach(){
    	memberRepository.clearStore();
    }
    
    @Test
    void 회원가입() {
    	//given
        Member member = new Member();
        member.setName("hello"); //hello 가 아니고 spring이라고 하면 에러 ("중복 회원 예외" 함수 실행 시)
        
        //when
        Long saveId = memberService.join(member);
        
        //then
        // Optional<Member> one = memberservice.findOne(saveId).get(); 라고 해도 되지만 단순하게 아래와 같이 해주는 게 좋다.
        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)); // 뒤쪽의 로직이 실행되면 IllegalStateException이라는 예외가 터짐
        
        assertThat(e.getMessage()).isEqualTo("이미 존재하는 회원입니다."); //위 37번째줄 검증
        
        try{
        	memberService.join(member2);
            fail()
        }catch (IllegalStateException e){
        	assertThat(e.getMessage().isEqualTo("이미 존재하는 회원입니다.")) //서비스 코드 IllegalStateException의 문구와 똑같아야 함 -> 비교
        }
        //then
        
    }
    
    @Test
    void findMembers()
}

 

 

+ MemoryMemberRepository 

+ MemberRepository

 

MemberService의 MemoryMemberRepository와 MemberServiceTest의 MemoryMemberRepository는 서로 다른 객체이므로 생성자를 사용해주면 좋다.

그러면 MemberService와 MemberServiceTest 는 다음과 같이 바꾸어 사용할 수 있다.

 

<MemberService>

 

<MemberServiceTest>

beforeEach 해서 넣어줌 -> dependency injection