서비스, 도메인, 레포지토리

naeganugu·2022년 7월 4일
0

스프링 마스터🌱

목록 보기
2/19

예전에 캡스톤 하면서 controller랑 service랑 domain이랑 뭐가 뭔지 모르지만 그냥 눈치껏 썼던 기억이 난다.
이제 제대로 알아보자!

1. 비지니스 요구사항 정리

일반적인 웹 애플리케이션 계층 구조는 다음과 같다.

  • 컨트롤러: 컨트롤러 혹은 API
  • 도메인: 주로 데이터베이스에 저장하고 관리되는 비지니스 도메인 객체. ex. 회원, 주문, 쿠폰 등등
  • 서비스: 핵심 비지니스 로직. ex. 회원은 중복가입이 안된다 등의 로직

서비스는 비지니스 도메인 객체를 가지고 핵심 비지니스 로직을 구현한 계층이다. 즉, Member 도메인 객체가 있으면 이걸로 서비스에서 회원가입, 중복가입 방지 등을 구현한다.

프로젝트 구조는 이런 식! controller, domain, repository 폴더로 나뉜다.

2. 개발과 테스트

이제 간단하게 회원 등록과 조회가 되는 비지니스를 만들어 볼 건데, 기본적인 비지니스 요구사항은 다음과 같다.

비즈니스 요구사항 정리

  • 데이터: 회원ID, 이름
  • 기능: 회원 등록, 조회
  • 아직 데이터 저장소가 선정되지 않음(가상의 시나리오)

크게 개발부와 개발이 잘 되었는지 테스트하는 테스트부가 있다.
테스트 없이 개발하는 건 말도 안 되는 일. 테스트는 동시에 여러 개를 돌릴 수도 있고 여러 장점이 많다. 선택이 아닌 필수.

이 예제에서는 개발을 먼저 한 뒤에, 테스트 케이스를 작성했다. 하지만 반대의 경우로 개발도 가능하다.

TDD: 테스트 주도 개발. 개발을 먼저 한 뒤에 테스트를 작성하는 방식이 아닌, 이를 뒤집어서 우선 테스트 클래스를 먼저 적성 후 개발 할 수도. 이런 방식을 TDD.

개발부는 그래도 캡스톤을 하면서 많이 써봐서 그런지, 위 예제로서는 이해가 안되는 부분이 없었다. 그래서 패스.. 테스트 케이스 만드는 게 어색했기에 그 부분을 조금 정리하고자 한다.

테스트도 그냥 소스코드 부분이랑 비슷한 구조를 가진다. 직접 패키지랑 파일을 추가해서 테스트를 만들 수도 있지만 단축키를 쓰면 간단하다.

테스트 생성 단축키: Command + shift + t


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();
        assertThat(member.getName()).isEqualTo(findMember.getName());
    }

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

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

        // when
        memberService.join(member1);
        IllegalStateException e = assertThrows(IllegalStateException.class, // IllegalStateException 예외가 발생해야 한다.
                () -> memberService.join(member2));//예외가 발생해야 한다. assertThat(e.getMessage()).isEqualTo("이미 존재하는 회원입니다.");

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

    
}

@BeforeEach는 테스트 실행 전에 실행되고,
@AfterEach는 테스트 실행 후에 실행된다.
위 코드에서는 테스트 전에 service에 repository를 넘겨주고(BeforeEach), 테스트 후에 repository를 싹 지워준다(AfterEach).
AfterEach로 지워주지 않으면 메모리 DB에 직전 테스트 결과가 남아있을 수 있다. 이렇게 되는 다음 테스트에서 실패할 수 있기 때문에 각 테스트가 종료될 때마다 repository를 비워주는 기능을 실행한다. 테스트는 순서에 의존하지 않고 각각 독립적으로 실행되도록 해야한다.

A 테스트가 먼저 실행되어야 B 테스트가 통과하는 건 좋지 않은 테스트!

void 회원가입()은 이름 그대로 회원가입이 잘 되는지 테스트 해준다. 테스트에서는 잘 되는 경우도 중요하지만, 예외에서 잘 처리가 되는지 등을 확인하는 것도 중요. 그래서 중복 회원이 잘 예외처리 되는지도 테스트로 확인한다.



[출처]

스프링-입문-스프링부트

profile
seungseung-zanggu

0개의 댓글