가상의 시나리오
package hello.hellospring.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;
}
}
package hello.hellospring.repository;
import hello.hellospring.domain.Member;
import java.util.List;
import java.util.Optional;
public interface MemberRepository {
Member save(Member member);
Optional<Member> findById(Long id);
Optional<Member> findByName(String name);
List<Member> findAll();
}
package hello.hellospring.repository;
import hello.hellospring.domain.Member;
import java.util.*;
public class MemoryMemberRepository implements MemberRepository{
private static Map<Long, Member> store= new HashMap<>();
private static long sequence = 0L; //key값을 생성해주는 것
@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(); //하나라도 찾는것, 하나라도 찾아서 있으면 반환해주지만, 끝까지 없으면 Optional에 null이 포함돼서 반환됨
}
@Override
public List<Member> findAll() { //지금까지 저장된 회원의 id를 전부 반환해줌
return new ArrayList<>(store.values());
}
}
위의 작성한 코드가 잘 동작하는지 보기 위해 테스트 케이스를 작성해본다!
개발한 기능을 실행해서 테스트 할 때 자바의 main 메서드를 통해서 실행하거나, 웹 애플리케이션의 컨트롤러를 통해서 해당 기능을 실행한다.
이러한 방법은 준비하고 실행하는데 오래 걸리고, 반복 실행하기 어렵고 여러 테스트를 한번에 실행하기 어렵다는 단점이 있다.
자바의 JUnit 이라는 프레임워크로 테스트를 실행해서 이러한 문제를 해결한다.
package hello.hellospring.repository;
import hello.hellospring.domain.Member;
import org.assertj.core.api.Assertions;
import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.Test;
import java.util.List;
import java.util.Optional;
import org.assertj.core.api.Assertions;
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();
// System.out.println("result= " + (result == member));
// Assertions.assertEquals(member, result); //
Assertions.assertThat(member).isEqualTo(result); //member가 result와 같다.
}
@Test
public void findByName(){
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();
Assertions.assertThat(result).isEqualTo(member1);
}
@Test
public void findAll(){
Member member1 = new Member();
member1.setName("spring1");
repository.save(member1);
Member member2 = new Member();
member2.setName("spring2");
repository.save(member2);
//when
List<Member> result = repository.findAll();
//then
Assertions.assertThat(result.size()).isEqualTo(2);
}
}
public void clearStore(){
store.clear();
}
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){
//같은 이름이 있는 중복 회원X
// Optional<Member> result = memberRepository.findByName(member.getName());
// result.ifPresent(m->{ //Optional로 감싸면 ifPresent를 사용할 수 있음.
// throw new IllegalStateException("이미 존재하는 회원입니다.");
// });
validateDuplicateMember(member); //중복 회원 검증
memberRepository.save(member);
return member.getId();
}
private void validateDuplicateMember(Member member) {
memberRepository.findByName(member.getName())
.ifPresent(m->{ //Optional로 감싸면 ifPresent를 사용할 수 있음.
throw new IllegalStateException("이미 존재하는 회원입니다.");
});
}
//전체 회원 조회
public List<Member> findMembers(){
return memberRepository.findAll();
}
public Optional<Member> findOne(Long memberId){
return memberRepository.findById(memberId);
}
}
클래스에서 ctrl + shift + t 하면 test 생성됨.
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();
private final MemberRepository memberRepository; //테스트할 때 같은 레퍼지를 쓰기 위해 위와 같은 코드가 아닌 이와 같은 코드로 작성하고 Test 코드도 @BeforeEach로 수정해줌
public MemberService(MemberRepository memberRepository) { //외부에서 넣어주도록 바꾸면 테스트할 때 쓰는 것과 같음
this.memberRepository = memberRepository;
}
// 회원가입
public Long join(Member member){
//같은 이름이 있는 중복 회원X
// Optional<Member> result = memberRepository.findByName(member.getName());
// result.ifPresent(m->{ //Optional로 감싸면 ifPresent를 사용할 수 있음.
// throw new IllegalStateException("이미 존재하는 회원입니다.");
// });
validateDuplicateMember(member); //중복 회원 검증
memberRepository.save(member);
return member.getId();
}
private void validateDuplicateMember(Member member) {
memberRepository.findByName(member.getName())
.ifPresent(m->{ //Optional로 감싸면 ifPresent를 사용할 수 있음.
throw new IllegalStateException("이미 존재하는 회원입니다.");
});
}
//전체 회원 조회
public List<Member> findMembers(){
return memberRepository.findAll();
}
public Optional<Member> findOne(Long memberId){
return memberRepository.findById(memberId);
}
}
@BeforeEach : 각 테스트 실행 전에 호출된다. 테스트가 서로 영향이 없도록 항상 새로운 객체를 생성하고,
의존관계도 새로 맺어준다.