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

회원 도메인과 회원 레포지토리 만들기
domain.Member
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;
}
}
repository.MemberRepository
public interface MemberRepository {
Member save(Member member);
Optional<Member> findById(Long id);
Optional<Member> findByName(String name);
List<Member> findAll();
}
repository.MemoryMemberRepository
@Repository
public class MemoryMemberRepository implements MemberRepository {
private static Map<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) {
// null이어도 반환 가능하게 함
return Optional.ofNullable(store.get(id));
}
@Override
public Optional<Member> findByName(String name) {
return store.values().stream()
.filter(member -> member.getName().equals(name))
.findAny();
}
@Override
public List<Member> findAll() {
return new ArrayList<>(store.values());
}
public void clearStore(){
store.clear(); //테스트 코드를 실행할 때 각 테스트 실행 후 동작
}
}
회원 레포지토리 테스트 케이스 작성
repository.MemoryMemberRepositoryTest
public class MemoryMemberRepositoryTest {
MemoryMemberRepository repository = new MemoryMemberRepository();
@AfterEach //각 테스트 실행 후 store를 초기화 시킴
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.assertEquals(member, result);
assertThat(member).isEqualTo(result);
}
@Test
public void findByNameTest(){
Member member1 = new Member();
member1.setName("spring1");
repository.save(member1);
Member member2 = new Member();
member2.setName("spring2");
repository.save(member2);
Member result = repository.findByName("spring1").get();
assertThat(result).isEqualTo(member1);
}
@Test
public void findAllTest(){
Member member1 = new Member();
member1.setName("spring1");
repository.save(member1);
Member member2 = new Member();
member2.setName("spring2");
repository.save(member2);
List<Member> result = repository.findAll();
assertThat(result.size()).isEqualTo(2);
}
}
테스트의 순서는 보장되지 않아 순서에 의존적으로 작성하면 안된다.
@AfterEach를 통해 테스트마다 영향을 끼치지 않도록 한다.
회원 서비스 개발
service.MemberService
@Service
@Transactional
public class MemberService {
//private final MemberRepository memberRepository = new MemoryMemberRepository();
private final MemberRepository memberRepository;
@Autowired
public MemberService(MemberRepository memberRepository){
this.memberRepository = memberRepository;
}
//회원가입
public Long join(Member member){
//같은 이름이 있는 중복 회원 있을 경우 예외 발생
validateDuplicateMember(member);
memberRepository.save(member);
return member.getId();
}
private void validateDuplicateMember(Member member) {
memberRepository.findByName(member.getName()) //Optional<Member>가 반환됨.
.ifPresent(m -> {
throw new IllegalStateException("이미 존재하는 회원입니다.");
});
}
//전체 회원 조회
public List<Member> findMembers(){
return memberRepository.findAll();
}
public Optional<Member> findOne(Long id){
return memberRepository.findById(id);
}
}
회원 서비스 테스트
service.MemberServiceTest
class MemberServiceTest {
MemberService memberService;
MemoryMemberRepository memberRepository;
@BeforeEach //MemberService에 있는 memberRepository와 Test에 있는 memberRepository가 다른 객체이므로 맞춰 줌.
public void beforeEach(){ //DI. 외부에서 MemoryMemberRepository를 넣어줌
memberRepository = new MemoryMemberRepository();
memberService = new MemberService(memberRepository);
}
@AfterEach
public void afterEach(){
memberRepository.clearStore();
}
@Test
void 회원가입() { //테스트 메서드 이름은 한글로 작성 가능
//given
Member member1 = new Member();
member1.setName("spring");
//when
Long saveId = memberService.join(member1);
//then
Member findMember = memberService.findOne(saveId).get();
assertThat(member1.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);
//memberService.join(member2)를 실행했을 때 IllegalStateException 예외가 발생해야 테스트 통과.
IllegalStateException e = assertThrows(IllegalStateException.class,
() -> memberService.join(member2));
//then
assertThat(e.getMessage()).isEqualTo("이미 존재하는 회원입니다.");
}
}
@BeforeEach : 각 테스트 실행 전에 호출된다. 테스트가 서로 영향이 없도록 항상 새로운 객체를 생성하고, 의존관계도 새로 맺어준다.