ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • 테스트 코드 - 회원 관리 예제 실습(회원 서비스 개발)
    테스트코드(Test Code) 2022. 2. 14. 00:01

    이전에 회원 관리 예제를 작성하는 실습(회원 서비스 개발)을 진행하였습니다.

    이를 통해 테스트 코드를 작성해보고자 합니다.

     

    https://junuuu.tistory.com/93

     

    1. src/test/java 에 hello.hellospring.service 패키지를 생성합니다.

    2. hello.hellospriong.service패키지에 MemberServiceTest 클래스를 생성합니다.

    일반적으로 테스트하고자 하는 클래스 이름 뒤에 Test를 붙여 이름 짓습니다.

     

    3. MemberServiceTest 클래스에 테스트 코드를 작성합니다.

    package hello.hellospring.service;
    
    import static org.junit.jupiter.api.Assertions.assertThrows;
    import static org.junit.jupiter.api.Assertions.fail;
    
    import org.assertj.core.api.Assertions;
    import org.junit.jupiter.api.AfterEach;
    import org.junit.jupiter.api.BeforeEach;
    import org.junit.jupiter.api.Test;
    
    import hello.hellospring.domain.Member;
    import hello.hellospring.repository.MemoryMemberRepository;
    
    public class MemberServiceTest {
    
    	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("hello");
    		
    		//when
    		Long saveId = memberService.join(member);
    		
    		//then
    		Member findMember = memberService.findOne(saveId).get();
    		Assertions.assertThat(member.getName()).isEqualTo(findMember.getName());
    		
    	}
    	
    	@Test
    	void 중복_회원_예외() {
    		//given
    		Member member1 = new Member();
    		member1.setName("hello");
    		
    		Member member2 = new Member();
    		member2.setName("hello");
    		
    		
    		//when
    		memberService.join(member1);
    		IllegalStateException e =assertThrows(IllegalStateException.class, () -> memberService.join(member2));
    		/*		
    		try {
    			memberService.join(member2);
    			fail();
    		} catch (IllegalStateException e) {
    			Assertions.assertThat(e.getLocalizedMessage()).isEqualTo("이미 존재하는 회원입니다.");
    		}
    		*/
    		//then
    		Assertions.assertThat(e.getMessage()).isEqualTo("이미 존재하는 회원입니다.");
    		
    	}
    
    	@Test
    	void findMembers() {
    
    	}
    
    	@Test
    	void findOne() {
    
    	}
    
    }

     

    테스트 메서드에는 "회원가입" 처럼 한글을 사용해도 됩니다.

     

    테스트를 하기위해 MemberService 객체를 생성합니다.

     

    테스트 코드는 given - when -then 패턴을 사용합니다.

     

    given을 통해 어떤 데이터가 주어지는지 when을 통해 어떤 것을 검증하는구나 then을 통해 결과가 어떤지를 알 수 있습니다.

     

    위의 회원가입 메서드에서는

    given을 통해 hello이름을 가진 member 데이터가 주어지는 것을

    when을 통해 memberService.join 메서드를 검증하는 것을

    then을 given의 데이터와 방금 저장된 데이터가 동일한지 비교하는 것을 알 수 있습니다.

     

    join의 핵심은 중복 회원 검증기능도 중요하기 때문에 중복 회원이 들어왔을때 예외를 잘 처리하는지도 중요합니다.

     

    중복_회원_예외 메서드는 2개의 member 객체를 선언하여 이름을 동일하게 설정합니다.

    이후에 람다식으로 검증하는방법도 있으며, 주석된 try-catch를 활용하여 검증할 수도 있습니다.

    하지만 회원가입 메서드에서 이미 회원가입을 했기 때문에 첫 번째에서 중복 예외가 발생하면서 제대로 된 테스트가 진행되지 않을 수 있기 때문에 Test를 한번 돌 때마다 리포지토리를 clear 해주어야 합니다.

     

    따라서 memberRepository 객체를 생성하고 AfterEach 어노테이션을 적용한 후, afterEach() 메소드를 작성하여 Test를 한번 돌 때마다 리 포티토 리를 clear 시킵니다.

     

    하지만 MemberService에 존재하는 memberRepository와 테스트코드에서 생성하는 memberRepository는 다른 객체이기 때문에 문제가 발생할 여지가 있습니다. (여기서는 static 변수를 사용했기 때문에 괜찮았습니다.)

    (다른 객체 = 참조하고 있는 메모리 주소가 다름)

     

    따라서 이것을 같은 인스턴스를 쓰도록 해야 합니다.

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

    위의 코드는 MemberService 클래스에서 생성자를 통해 MemberRepository를 할당받습니다.

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

    위의 코드는 테스트코드에서 @BeforeEach 어노테이션을 사용하여 각 테스트가 일어나기 전에 메모리 리포지토리를 새로 생성하여 이를 MemberService에 넣어줍니다. 이렇게 되면 테스트에서 사용하는 리포지토리와 MemberService에서 사용하는 리포지토리가 같은 인스턴스가 됩니다.

     

    MemberService입장에서는 직접 인스턴스를 생성하지 않고 외부에서 생성하여 넣어주기 때문에 이를 Dependency Injection인 DI라고 합니다.

     

    강의에서는 findMembers()와 findOne() 테스트는 구현하지 않았는데 이를 직접 구현해 보도록하겠습니다.

    @Test
    	void findMembers() {
    		//given
    		Member member1 = new Member();
    		member1.setName("hello1");
    		
    		Member member2 = new Member();
    		member2.setName("hello2");
    		
    		memberService.join(member1);
    		memberService.join(member2);
    		
    		//when
    		List<Member> result = memberService.findMembers();
    		
    		//then
    		Assertions.assertThat(result.size()).isEqualTo(2);		
    	}
    
    	@Test
    	void findOne() {
    		//given
    		Member member = new Member();
    		member.setName("hello");
    				
    		memberService.join(member);
    		Long memberId = member.getId();
    				
    		//when
    		Member result = memberService.findOne(memberId).get();
    				
    		//then
    		Assertions.assertThat(result.getName()).isEqualTo(member.getName());		
    	}

    주의할 점은 findOne() 테스트 코드를 작성할 때

    memberService.join(member)와 Long memberId = member.getID()의 순서가 바뀌게 되면

    memberId에 null값이 할당되어 테스트가 실패하게 됩니다.

    이유는 join(회원가입)을 할때 내부적으로 memberId를 더해서 할당하므로 join이 일어나지 않으면 member 객체는 id값을 가지지 않아 null을 가지기 때문입니다.

     

    댓글

Designed by Tistory.