인프런 스프링 입문(10)

🦥 회원서비스테스트

회원서비스를 개발하였으니 회원서비스를 테스트 해보자

테스트를 이미 진행해본, repository 밑에 service 폴더를 만들고 MemberServiceTest.java의 파일을 만들어준다. 그러고나서 다음과 같은 텍스트를 입력해준다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
package com.spring_study.d03_16.service;

import com.spring_study.d03_16.domain.*;
import com.spring_study.d03_16.repository.MemberRepository;
import com.spring_study.d03_16.repository.MemoryMemberRepository;

import static org.assertj.core.api.Assertions.*;

import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;





public class MemberServiceTest {
    // 테스트는 객체를 한글로 바꾸어도 된다.

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

    //member 서비스에서 있는 memberRepository 는 새로운 객체 new MemoryMemberRepositroy.이다. 

    @BeforeEach //-> 테스트 실행하기 전부터 각각 생성을해준다. 그 다음 처음코드로 실행하게 되면서 각각 new 객체를 집어넣게 해준다. (Dependency injection) -> di에 관련된건 다음시간에
     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();
        assertThat(member.getName()).isEqualTo(findMember.getName());
    }
    @Test
    public void 중복_회원_예외(){
        //given
        Member member1 = new Member();
        member1.setName("spring");
        
        Member member2 = new Member();
        member2.setName("spring");
        
        //when
        memberService.join(member1);
        IllegalStateException e = Assertions.assertThrows(IllegalStateException.class, () -> memberService.join(member2));

        assertThat(e.getMessage()).isEqualTo("이미 존재하는 회원입니다.");

        /* try {
            memberService.join(member2); //validateDuplicateMember 에서 예외로 터져야한다.
            fail("예외가 발생해야 합니다.");
        } catch (IllegalStateException e) {
            // TODO: handle exception
            assertThat(e.getMessage()).isEqualTo("이미 존재하는 회원입니다.");
        } */
        

        //then
    }

    @Test
    void testFindMembers() {

    }

    @Test
    void testFindOne() {

    }
}

일단 테스트를 진행하면서 좀 더 직관적으로 테스트를 진행할 수 있는 방법을 말씀해주셨는 데. 바로 //give //when //then이다.
말 그대로 무엇을 받고 무엇을하고 그다음에 뭐가나오나? 라는 의미이다.
좀 많이 괜찮은 거 같다. 일반적인 상황에서도 짧은 코드를 치더라도 내가 어떤 값을 어떻게 처리해서 어떻게 한다. 라는건 직관적으로 많이 필요한것 같다… 주석을 애용하자.

try-catch가 애매한 이유

나도 이게 왜 애매한 이유인지 궁금했지만 역시 나말고 궁금한사람은 있었다. 역시 생각하는 건 비슷하다… 아마도 모두 보라고 답을 남겨 주셨기 때문에 주석처리한 try-catch말고 메세지를 받아서 한 이유를 알려주신다.

상세 코드 공부


1) 테스트 코드의 의도가 불명확해질 수 있습니다. 예를 들어 위의 테스트 코드는 같은 이름을 가진 회원이 이미 존재할 때 회원가입을 시도하면 회원서비스에서 예외를 반환하는 것을 검증하기 위한 의도를 가지고 있습니다. 그리고 try-catch 문은 보통 try 문의 예외를 잡아 정상처리해주기 위해서 사용합니다. 그러면 위의 코드에서 해당 예외를 잡아 처리해주는 것은 테스트 코드의 의도와는 다소 맞지 않아보일 수 있습니다. 예외가 정상적으로 터지는 것을 보고 싶은데, try-catch 문으로 예외를 잡아서 처리해주는 것은 협업하는 다른 개발자로 하여금 혼란을 줄 수 있다 생각합니다 :)

2) 두번째로는 try-catch문을 사용하는 것보다 테스트 프레임워크의 기능을 사용하는 것이 훨씬 가독성이 좋습니다. JUnit에 내장되어있는 assertThrows()Assertions 모듈의 assertThatThrownBy()와 같은 메서드를 활용하면 이 테스트가 예외를 반환하고 이를 확인하기 위한 코드라는 것을 훨씬 더 짧은 코드로 가독성 있게 보여줄 수 있는 것 같습니다.

감사합니다..서포터즈분..(y2gcoder)

이번코드는 뭔가 새로운것 내가 잘 알지못하는 것을 많이 해서 그런지 코드 해석을 하면서 공부해야겠다고 생각했다.

특히 처음 객체를 선언하는 것은 그렇다 하셨는 데 메소드 두개를 쓰는것과 static 을 쓰는것은 무슨 문제가 있는지.. 자바책을 다시 열어봐야겠다. 어쨋든 di도 그렇고공부를 더 많이 해야겠다.

Leave a comment