회원 레포지토리
@Repository //ComponentScan 에 의해 스프링 빈으로 등록.
@RequiredArgsConstructor
public class MemberRepository {
//@RequiredArgsConstructor로 생성자 주입.
private final EntityManager em;
public Long save(Member member){
em.persist(member);
return member.getId();
}
public Member findOne(Long id){
return em.find(Member.class,id);
}
public List<Member> findAll(){
return em.createQuery("select m from Member m", Member.class)
.getResultList();
}
public List<Member> findByName(String name){ //parameter를 binding
return em.createQuery("select m from Member m where m.name = :name", Member.class)
.setParameter("name",name )
.getResultList();
}
}
회원 서비스
@Service
@Transactional //jpa의 데이터 변경이나 로직은 트랜잭션 안에서 수행 해야 한다.
//@AllArgsConstructor //필드에 있는 변수들에 대한 생성자를 만들어줌.
@RequiredArgsConstructor //final로 생성된 변수들만 생성자를 만들어줌.
public class MemberSerivce {
//@Autowired //변경할 일 없으므로 final로 생성.
private final MemberRepository memberRepository;
//테스트 코드를 작성하거나 변경이 필요할 때 유리.
//생성자가 하나만 있을경우 @Autowired 애노테이션이 없어도 자동으로 주입됨.
// public MemberSerivce(MemberRepository memberRepository) {
// this.memberRepository = memberRepository;
// }
//회원 가입
@Transactional
public Long join(Member member){
//중복 회원 검증
validateDuplicateMember(member);
memberRepository.save(member);
return member.getId();
}
private void validateDuplicateMember(Member member) {
//EXCEPTION
List<Member> findMembers = memberRepository.findByName(member.getName());
if (!findMembers.isEmpty()) {
throw new IllegalStateException("이미 존재하는 회원입니다.");
}
}
//회원전체 조회
@Transactional(readOnly = true) //데이터의 변경이 없는 읽기 전용 메서드에 사용, 영속성 컨텍스트를 플러시 하지 않으므로 약간의 성능 향상(읽기 전용에는 다 적용)
public List<Member> findMembers(){
return memberRepository.findAll();
}
@Transactional
public Member findOne(Long memberId){
return memberRepository.findOne(memberId);
}
}
회원 기능 테스트
@RunWith(SpringRunner.class)
@SpringBootTest //스프링을 통한 테스트
@Transactional //기본적으로 롤백 수행. 테스트를 반복적으로 하기 위해 db에 데이터를 남기지 않기 위함.
class MemberSerivceTest {
@Autowired MemberSerivce memberSerivce;
@Autowired MemberRepository memberRepository;
@Test
public void 회원가입() throws Exception{
//given
Member member = new Member();
member.setName("kim");
//when
Long saveId = memberSerivce.join(member);
//then
Assert.assertEquals(member, memberRepository.findOne(saveId));
}
@Test
public void 중복_회원_예외(){
//given
Member member1 = new Member();
member1.setName("lee");
Member member2 = new Member();
member2.setName("lee");
//when
memberSerivce.join(member1);
//IllegalStateException이 발생하면 catch 해줌으로써 테스트 통과.
assertThrows(IllegalStateException.class, () -> {memberSerivce.join(member2);});
//then
}
}
테스트 케이스를 위한 설정
테스트는 케이스 격리된 환경에서 실행하고, 끝나면 데이터를 초기화하는 것이 좋다. 그런 면에서 메모리 DB를 사용하는 것이 가장 이상적이다.
스프링 부트는 datasource 설정이 없으면, 기본적을 메모리 DB를 사용하고, driver-class도 현재 등록된 라이브러리를 보고 찾아준다.
추가로 ddl-auto 도 create-drop 모드로 동작한다. 따라서 데이터소스나, JPA 관련된 별도의 추가 설정을 하지 않아도 된다.