회원 리포지토리와 도메인을 이용해서 실제 비지니스 로직을 작성하는 곳
고객 객체인 memberRepository (인터페이스)을 이용해서 서비스 기능을 구현
public class MemberService {
private final MemberRepository memberRepository = new MemoryMemberRepository();
/**
* 회원 가입
*/
public Long join(Member member){
//같은 이름이 있는 중복회원은 안된다는 조건 추가
validateDuplicateMember(member);
memberRepository.save(member);
return member.getId();
}
private void validateDuplicateMember(Member member) {
memberRepository.findByName(member.getName())
.ifPresent(m -> {
throw new IllegalStateException("이미 존재하는 회원입니다");
});
}
/**
* 전체 회원 조회
*/
private List<Member> findMembers() {
return memberRepository.findAll();
}
public Optional<Member> findOne(Long memberId){
return memberRepository.findById(memberId);
}
}
테스트를 진행할 클래스의 클래스명에서 (지금은 MemberService) cmd-shift-t를 입력하면 자동으로 각 메소드에 대한 Test 기본 틀을 만들어 준다
@Test를 짤때 given
, when
, then
으로 구분지어서 짜는것이 좋다
@Test메소드는 한글명으로 하는 경우도 흔하다, 매우 직관적이므로
MemberService memberService;
MemoryMemberRepository memberRepository;
@BeforeEach
public void beforeEach(){
memberRepository = new MemoryMemberRepository();
memberService = new MemberService(memberRepository);
}
@AfterEach
public void afterEach(){
memberRepository.clearStore();
}
@Test
void 회원가입() {
//given
Member member = new Member();
member.setName("woonsik");
//when
Long saveId = memberService.join(member);
//then
Member findMember = memberService.findOne(saveId).get();
assertThat(member.getName()).isEqualTo(findMember.getName());
}
@Test
public void 중복_회원_예외() {
//given
Member member1 = new Member();
member1.setName("woonsik1");
Member member2 = new Member();
member2.setName("woonsik1");
//when
memberService.join(member1);
//then
/*
try-catch 사용한 경우
try {
memberService.join(member2);
} catch (IllegalStateException e){
assertThat(e.getMessage()).isEqualTo("이미 존재하는 회원입니다");
}
*/
//assertThrows를 사용한 경우 -> 내가 원하는 예외클래스가 터지는지 학인한다
assertThrows(IllegalStateException.class, () -> memberService.join(member2));
//반환값으로 받아서 추가적인 확인도 가능하다
IllegalStateException e =
assertThrows(IllegalStateException.class, () -> memberService.join(member2));
assertThat(e.getMessage()).isEqualTo("이미 존재하는 회원입니다");
}
public class MemberService {
private final MemberRepository memberRepository;
//Dependency Injection == DI
//현 클래스에서 생성하는 것이 아닌 외부에서 생성한 것을 넣어주는 형태
public MemberService(MemberRepository memberRepository) {
this.memberRepository = memberRepository;
}
//~내용~
}
MyClass가 AnotherClass에 의존관계에 있는 상황이다
만약 AnotherClass가 변경된다면 (인자가 String-> Integer 등) MyClass의 변경 또한 필요하다는 것이 명확하다
public class MyClass1{
private AnotherClass anotherClass;
public MyClass1(){
this.anotherClass = new AnotherClass("언아더클래스");
anotherClass.printName();
}
}
이러한 의존 관계를 피하기 위해서 anotherClass를 더이상 MyClass에서 configure하지 않고
생성자의 인자로 받아버리는 것이다
이를 '의존성이 주입되었다' 또는 '제어가 역전되었다'라고 표현한다
실제로 "언아더클래스"라는 인자로 configured된 anotherClass를 받아야 한다는 사실을
더이상 MyClass는 알필요가 없게 되었다. 즉, 의존관계가 없어졌다
이를 통해 코드의 재사용성, Test 용이성을 얻을 수 있다
public class MyClass {
private AnotherClass anotherClass;
public MyClass(AnotherClass anotherClass){
this.anotherClass = anotherClass;
this.anotherClass.printName();
}
}