본문 바로가기
Study/Java Spring Boot

[Spring] 스프링 입문3 - 회원 서비스 개발

기본예제인 회원 도메인과 서비스를 만들어보자.

domain 패키지를 만들어 회원데이터를 전달할 Member 객체를 만들고, (DTO)

repository 패키지를 만들어 회원을 저장하고 조회기능을 가지도록 만들어보자. 

 

일단 DB가 정해지지않았다고 가정하여 개발한다.

추후 소스코드의 변경없이 간단하게 연결을 바꿀수 있기 때문이다.

 

com.example.intro.domain / Member.java 객채

package com.example.intro.domain;

public class Member {
	private Long id;
	private String name;
	
	public Long getId() {
		return id;
	}
	public void setId(Long id) {
		this.id = id;
	}
	public String getName() {
		return name;
	}
	public void setName(String name) {
		this.name = name;
	}
	
	
}

 

getter / setter 제너레이팅 단축키  -  ALT+ SHIFT+ S ,  R 

 

 

com.example.intro.repository MemberRepository.java 인터페이스

package com.example.intro.repository;

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

import com.example.intro.domain.Member;

public interface MemberRepository {
	Member save(Member member);
	Optional<Member> findById(Long id);
	Optional<Member> findByName(String name);
	List<Member> findAll();
}

 

com.example.intro.repository MemoryMemberRepository 구현클래스

package com.example.intro.repository;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Optional;

import org.springframework.stereotype.Repository;

import com.example.intro.domain.Member;

@Repository
public class MemoryMemberRepository implements MemberRepository{
	private static HashMap<Long, Member> store = new HashMap<>();
	private static long sequence = 0L;
	
	
	@Override
	public Member save(Member member) {
		member.setId(++sequence);
		store.put(member.getId(),member);
		return member;
	}
	
	@Override
	public Optional<Member> findById(Long id) {
		return 	Optional.ofNullable(store.get(id));  
	}

	@Override
	public Optional<Member> findByName(String name) {
		return store.values().stream()
			.filter(member -> member.getName().equals(name))
			.findAny(); // values를 stream객체로 반복문돌리듯 받아서, 객체의 이름이 찾는이름과 같은게 하나라도 있으면 반환
	}
	
	@Override
	public List<Member> findAll() {
		return new ArrayList<Member>(store.values());
	}
	
	public void clearStore() {
		store.clear();
	}
}

 

위와 같이 id와 name을 가지는 member객체를 만들고

해당 도메인을 사용에 실질적인 저장 , 반환을 하는 MemoryMemberRepository 객체를 만들어 주었다.

아직 DB를 사용하기 전이므로, HashMap에 아이디와 member객체를 넣어 id로 객체 접근이 가능하도록 한다.

 

com.example.intro.service MemberService 클래스

package com.example.intro.service;

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

import org.springframework.stereotype.Service;

import com.example.intro.domain.Member;
import com.example.intro.repository.MemberRepository;

@Service
public class MemberService {
	private final MemberRepository memberRepository;
	
	// Dependence Injection - 호출하는 외부에서 받아 넣어주며 생성하도록한다 -> 인스턴스 동기화를 위함
	public MemberService(MemberRepository memberRepostory) {
		this.memberRepository = memberRepostory;
	}
	
	// 회원가입
	public Long join(Member member) {
		vaildateDuplicateMember(member); // 중복검증
		memberRepository.save(member);
		return member.getId();
	}
	// 중복체크
	private void vaildateDuplicateMember(Member member) {
		 memberRepository.findByName(member.getName()).ifPresent(m ->{
				throw new IllegalStateException("이미 존재하는 회원 입니다.");
			});
	}
	// 전체 회원조회
	public List<Member> findMembers() {
		return memberRepository.findAll();
	}
	// 한 회원만 조회
	public Optional<Member> findOne(Long id){
		return memberRepository.findById(id);
	}
	
}

서비스 컴포넌트에서는 회원가입 , 회원조회 기능을 구현됐다.

이제 정상적으로 구현되었는지 테스트를 해야한다.

 

테스트 코드 작성

Spring에서 테스트는 src/test/java 밑에 테스트코드를 동일한 위치와 네이밍형식으로 작성한다.

아래와 같이  repository와 service 에 작성한 코드를 동일한 패키지명으로 뒤에 Test를 붙여서 만들어준다.

 

Spring 코드를 테스트할때는 junitassertj 라이브러리를 이용한다.

 

MemoryMemberRepositoryTest

package repository;

import java.util.List;

import org.assertj.core.api.Assertions;
import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.Test;

import com.example.intro.domain.Member;
import com.example.intro.repository.MemoryMemberRepository;

public class MemoryMemberRepositoryTest {
	MemoryMemberRepository repository = new MemoryMemberRepository();
	
	@AfterEach
	public void afterEach() { 
		repository.clearStore();
	}
	
	@Test
	public void save() {
		Member member = new Member();
		member.setName("Spring"); 
		repository.save(member);
		
		Member result = repository.findById(member.getId()).get();		
		Assertions.assertThat(member).isEqualTo(result);
	}	
	@Test
	public void findByName() {
		Member member = new Member();
		member.setName("Spring");
		repository.save(member);
		
		Member result = repository.findByName("Spring").get();
		Assertions.assertThat(member).isEqualTo(result);
	}
	
	@Test
	public void findAll() {
		Member member = new Member();
		member.setName("Spring1");
		repository.save(member);
		Member member2 = new Member();
		member2.setName("Spring2");
		repository.save(member2);
		
		List<Member> result= repository.findAll();
		Assertions.assertThat(result.size()).isEqualTo(2);

	}
	
	
}

테스트 어노테이션이 달리면 각각의 메소드를 전부 테스트하게 되는데.

순서를 보장하지 않으므로, 각각의 테스트마다 claer를 해주어야한다.

한 저장소 객체를 만들어서 AfterEach를 통해 각각의 메소드마다 저장소를 초기화해주면서 테스트한 것이다.

 

MemberServiceTest

package service;

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

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 com.example.intro.domain.Member;
import com.example.intro.repository.MemoryMemberRepository;
import com.example.intro.service.MemberService;

public class MemberServiceTest {

	MemoryMemberRepository mmr = new MemoryMemberRepository();
	MemberService ms = new MemberService(mmr);
	/*
	 @BeforeEach
	public void beforeEach() {
		ms = new MemberService(mmr);
	}*/
	
	@AfterEach
	public void afterEach() { 
		mmr.clearStore();
	}
	
	@Test	
	// 회원가입
	void join() {
		// given
		Member member = new Member();
		member.setName("spring1");
		// when
		Long id = ms.join(member);		
		// then
		Member testMem = ms.findOne(id).get(); 
		Assertions.assertThat(member).isEqualTo(testMem);
	}

	@Test	
	// 중복 회원가입
	void dup_join() {
		// given
		Member member = new Member();
		member.setName("Spring1");
		Member member2 = new Member();
		member2.setName("Spring1");

		// when
		Long id1 = ms.join(member);		
		assertThrows(IllegalStateException.class,() -> ms.join(member2));
	}
	
}

서비스에서 중복 회원가입까지 테스트해보았다.

여기서 beforeEach를 통해 테스트전 저장소 인스턴스를 새로이 만들어주도록 설정할 수 도있다.

서비스별로 독립적인 인스턴스를 가지고 테스트하고 싶은경우에 참고하자!

 

 

 

 

소스코드

https://github.com/bangbangu4/Spring-intro

 

GitHub - bangbangu4/Spring-intro: Spring-Introduction (김영한) 강의 정리

Spring-Introduction (김영한) 강의 정리. Contribute to bangbangu4/Spring-intro development by creating an account on GitHub.

github.com