[Spring] 회원 관리 예제 - 2

이준영·2022년 9월 22일
0

스프링-입문

목록 보기
7/15

회원 Repository 테스트 케이스 작성

코드를 작성하면 내가 작성한 코드가 제대로 실행되는지 확인해야한다.
그 방법에는 두가지가 있다.

  1. 수정한 코드를 저장하고 서버를 껐다 켜서 변경사항 반영
  2. 테스트 코드 작성

1번의 방법은 간단하지만 프로젝트의 크기가 커지면 커질수록 시간도 오래걸리고 귀찮아진다. 기업에서 진행되는 대규모 프로젝트의 경우에 이런 방법은 불가능하다고 봐도 될 것 같다.

그래서 2번의 방식을 채택했는데 원리는 간단하다.
test 디렉토리에서 테스트 클래스를 생성하여 main에서 정의한 함수를 테스트하는 것이다.

  1. Test Class 파일은 test 디렉토리 밑에서 main에서 테스트할 클래스가 있는 위치와 동일한 위치에 생성한다. 그러니까 main을 test로 바꾸면 그곳이 Test Class가 작성될 위치다.
    클래스 파일의 이름의 뒤에 Test를 붙여서 구분한다.

  2. class와 method는 다음과 같이 선언/생성한다
    테스트 함수는 @Test 애노테이션을 붙여서 정의한다.
    테스트 결과는 Assertions 라는 라이브러리의 assertThat()이라는 method로 확인하는데 이 Assertions가 junit에서 제공하는게 하나 있고, assertj에서 제공하는게 하나 있는데 assertj꺼를 많이 쓰는듯..?(쓰기 더 편함)
    assertj의 Assertions을 static으로 import하면 Assertions.assertTaht()으로 쓰던걸 asserThat()만 적어도 사용할 수 있다!!
    *단축키 : opiton + Enter

// 1. 테스트용 클래스 생성
public class MemoryMemberRepositoryTest {

    MemoryMemberRepository repository = new MemoryMemberRepository();
	
    @Test
    public void save(){
        Member member = new Member();
        member.setName("spring");
		
        // 2. main에서 정의한 함수 save()
        repository.save(member);
		
        // 3. 제대로 작동하는지 확인(테스트)
        Member result = repository.findById(member.getId()).get(); 
        assertThat(member).isEqualTo(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();
        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);

        List<Member> result = repository.findAll();

        assertThat(result.size()).isEqualTo(2);
    }

}

이렇게 작성 후 각가의 테스트 함수를 실행하면 에러가 안나는데 한번에 실행 했더니 오류가 발생했다.
서로 다른 두 테스트 함수에 같은 이름의 변수를 사용해서 생긴 오류였다.
즉 테스트1이 value라는 변수를 사용했는데 뒷정리를 안하고 갔는데 마침 테스트2도 value라는 변수가 필요해서 쓰려고 보니까 이미 누가 썼던거라서 에러가 나는 것이다!
당장에야 변수 이름을 바꾸면 해결이 되지만 근본적이 해결방법이 아니다. 그럼 어떡해?

테스트는 순서와 관계없이 짜야 한다

위에서는 테스트1, 테스트2 라는 이름으로 순서를 주었지만 테스트2가 먼저 value라는 변수를 쓸 수도있고 테스트3이라는 함수가 value라는 변수를 먼저 쓸 수도 있다
그래서 테스트 함수는 각각의 @Test가 실행되고 난 후 repository를 비워줘야한다.

이 뒷정리를 해주는게@AfterEach 애노테이션이다.
@AfterEach 함수는 각각의 @Test 함수가 실행 되고 나면 수행되는 함수이다

//
public class MemoryMemberRepositoryTest {

    MemoryMemberRepository repository = new MemoryMemberRepository();
	
    @AfterEach // @Test가 끝날 때마다 수행
    public void afterEach() { repository.clearStore(); }
    
    
    @Test
    public void save(){ ... }
    
    @Test
    public void findByName() { ... }

    @Test
    public void findAll() { ... }

}

@AfterEach로 @Test가 끝날 때마다 clearStore() method를 이용해 사용한 repository를 비워주고있다.


회원 서비스 테스트

회원가입

서비스는 전 포스터에서도 명시했듯이 비즈니스 로직을 구현하는 패키지이다.

class MemberServiceTest {

    MemberService memberService = new MemberService();
    MemoryMemberRepository memberRepository = new MemoryMemberRepository();

    @AfterEach // @Test가 끝날 때마다 수행
    public void afterEach() { ... }

    @Test
    void 회원가입() {
        //given
        Member member = new Member();
        member.setName("spring");

        //when
        Long saveId = memberService.join(member);

        //then
        Member findMember = memberService.findOne(saveId).get();
        assertThat(member.getName()).isEqualTo(findMember.getName());
    }

    @Test
    void findMembers() { ... }

    @Test
    void findOne() { ... }
}

이런식으로 Test 코드를 작성한다.
참고로 Test 코드를 작성 할때는 대부분 given/when/then의 구조로 이루어져있어서 저렇게 주석처리로 써놓은 다음에 코드를 작성하면 로직을 이해하기도 쉽고 코드를 어떻게 짜야할지 감이 쉽게 잡힌다고한다!!

  • given : 뭔가 주어졌을 때
  • when : 실행하면
  • then : 어떤 값(result)가 나와야한다


회원 가입 중복 방지

회원가입 로직에서 중복 회원 가입을 방지하려면 회원의 정보가 담겨있는 MemoryMemberRepository를 가져와서 들여다 봐야 하는데 이러한 경우
test에서 new MemoryMemberRepository를 생성해 버리면 main에서 생성한 MemoryMemberRepository와 서로 다른 리포지터리가 되어버린다.

그럼 어떻게 해야될까?

외부에서 양쪽(main, test)에 같은 MemoryMemberRepository를 넣어줘한다.
이러한 방식을 DI(Dependency Injection)이라고 한다.

main의 MemeoryMemberRepository에서 MemberRepository를 선언&생성하던것을
선언만하고 생성자를 만든다

//MemberRepository  memberRepository = new MemoryMeberRepository( );
private final MemberRepository  memberRepository;

public MemberService(MemberRepository memberRepository) {
	this.memberRepository = memberRepository;
}

test의 MemeoryServiceTest에서도 선언만 해주고 @BeforeEach 애노테이션을 이용하여 함수를 만든다.
@BeforeEach는 @AfterEach와 마찬가지로 @Test 시작할 때마다 실행된다
(여기 헷갈리네.. 다시 공부하고오자)
(이러면 DI가 된거래)

class MemberServiceTest {

    //MemberService memberService = new MemberService();
    //MemoryMemberRepository memberRepository = new MemoryMemberRepository();

    MemberService memberService;
    MemoryMemberRepository memberRepository;

    @BeforeEach
    public void beforeEach(){
        memberRepository = new MemoryMemberRepository();
        memberService = new MemberService(memberRepository);
    }

    @AfterEach // @Test가 끝날 때마다 수행
    public void afterEach() { ... }

    @Test
    void 회원가입() { ... }

    @Test
    public void 중복_회원_예외() {
        //given
        Member member1 = new Member();
        member1.setName("spring");

        Member member2 = new Member();
        member2.setName("spring");

        //when
        memberService.join(member1);

        //try-catch 사용
        /*
        try{
            memberService.join(member2);
            fail();
        } catch(IllegalStateException e){
            assertThat(e.getMessage()).isEqualTo("이미 존재하는 회원입니다.123");
        }
*/

        //then
        IllegalStateException e = assertThrows(IllegalStateException.class, () -> memberService.join(member2));
        assertThat(e.getMessage()).isEqualTo("이미 존재하는 회원입니다.");
    }

    @Test
    void findMembers() { ... }

    @Test
    void findOne() { ... }
}

Java 공부하자...

  • 예외처리(Exception e)
  • try-catch문
profile
화이팅!

0개의 댓글