본문 바로가기
Study/Java Spring Boot

[Spring] 핵심 원리 2-1 회원 도메인 개발과 테스트

본 글은 김영한님의 강의 내용을 바탕으로 정리한 글입니다.

 

스프링 핵심 원리 - 기본편 - 인프런 | 학습 페이지

지식을 나누면 반드시 나에게 돌아옵니다. 인프런을 통해 나의 지식에 가치를 부여하세요....

www.inflearn.com

 

개발환경 

- Java  : 11 Version (자바 17을 사용해보았지만 , 지원되지 않아 11로 다운그레이드 했습니다.)

- IDE :  InteliJ or Eclipse

 

1. 프로젝트 생성

https://start.spring.io/ 

Spring Boot는 개발중인 ShapShot이나 M1이 아닌 가장 높은 안정화 버전으로 선택합니다.

위 사이트에서 해당 내용과 같이 설정하여 초기파일을 다운받아 줍니다.

강의 소스코드를 제공드릴 예정이오니, 가능하다면 똑같은 이름으로 해주시는게 편할듯 합니다.

내려받은 파일에서 build.gradle 파일을 선택해서 Project로 Import해주시면

자동으로 의존적인 gradle package를 설치해줍니다. (조금 시간이 소요됨)

이후에 Run을 할수 있습니다.

Run전에 위와같이 Gradle Run 환경을 수정합니다

 

 

2. 프로젝트 기획

비즈니스 요구사항에 따라 설계내용은 아래와 같다.

# 회원
- 회원은 회원가입 , 회원조회 두 기능을 가진다
- 회원등급은 일반과 VIP 두가지 등급이 있다.
- DB가 결정 되지 않았지만, 일단 개발을 진행해야한다.

# 주문과 할인
- 웹에서 상품을 주문할 수 있다.
- 회원 등급별 할인 정책이 있고, 주문시 적용할 수 있다.
- 할인 정책은 VIP 1000원 고정 할인이 있다 (나중에 금액이 변경될 수 있음)
- 할인 정책은 추후 더 정해질 예정이다. 할인 정책이 사라질 수 도 있음

 

 

3. 회원 도메인 설계

 

작은 순수자바로만 개발을 진행하고

스프링 기술을  추후 사용할 예정이라고 한다.

회원서비스에서 회원 리포지토리에 접근하는 형식으로 진행될것인데,

회원 레포지토리는 위 그림과 같이 초기에는 메모리를 사용하도록 구현후에

DB가 정해지면, SOLID 규칙에 의거하여 확장되도록 인터페이스를 이용해 만들것이다.

 

 

각 객체간의 처음 구현될 서비스들과 연결관계는 아래와 같다.

사용자의 요청에 의한 서비스객체를 거쳐 회원Repo에 구현된 내용에 접근하는 방식으로 흘러간다.

 

4. 회원 도메인, 서비스, 테스트 개발

회원 도메인  member 개발 소스 목록 

 

4-1) Member객체와 Grade 필드

회원 객체인 Member는 Long id, String name, Grade 등급의 필드를 가진다.

package hello.core.member;

public class Member {
    private Long id;
    private String name;
    private Grade grade;

    public Member(Long id, String name, Grade grade) {
        this.id = id;
        this.name = name;
        this.grade = grade;
    }

    public Long getId() {
        return id;
    }

    public void setId(Long id) {
        this.id = id;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public Grade getGrade() {
        return grade;
    }

    public void setGrade(Grade grade) {
        this.grade = grade;
    }
}
public enum Grade {
    BASIC, VIP
}

 

4-2) Member 레포지토리

 

회원을 저장하는 도메인은 MemberRepository 이며,  회원가입인 Join과 회원조회기능인 findById를 갖도록 한다.

인터페이스로 깡통의 Repository 생성후

Memory 기반의 처리, JDBC기반의 DB연결, JPA기술기반의 구현체로 점차 확장가능하게 한다.

MemberRepository 인터페이스

package hello.core.member;
public interface MemberRepository {
    void save(Member member);

    Member findById(Long memberId);

}

MemoryMemberRepository 클래스

package hello.core.member;
import java.util.HashMap;
import java.util.Map;

public class MemoryMemberRepository implements MemberRepository {

    private final static Map<Long, Member> store = new HashMap<>();

    @Override
    public void save(Member member) {
        store.put(member.getId(),member);
    }

    @Override
    public Member findById(Long memberId) {
        return store.get(memberId);
    }
}

Map을 이용해서 ID를 통한 저장 및 조회를 간단히 작성.

 

4-3) MemberService

MemberService 를 만들어 회원 도메인에 접근, 수행을 호출 부분을 만들자. 

MemberService 인터페이스

package hello.core.member;
public interface MemberService {
    void join(Member member);

    Member findMember(Long memberId);
}

MemberServiceImpl 클래스 (impl은 구현체에 약어로 통상적으로 사용)

package hello.core.member;
public class MemberServiceImpl implements MemberService{

    private final MemberRepository memberRepository = new MemoryMemberRepository();

    @Override
    public void join(Member member) {
        memberRepository.save(member);
    }

    @Override
    public Member findMember(Long memberId) {
        return memberRepository.findById(memberId);
    }
}

이 부분의 코드를 작성하면서 불편한 느낌을 받았다면, 앞의 객체지향 SOLID를 잘 공부했다고 볼 수 있다!

 

회원 도메인과 서비스 부분을 잘(?) 작성했으니, 수행시켜보고 테스트 클래스도 만들어보자!

 

4-4) 수행 및 테스트

hello.core 밑에 MemberApp 클래스를 만들어 정상 동작여부를 확인해보자

package hello.core;

import hello.core.member.Grade;
import hello.core.member.Member;
import hello.core.member.MemberService;
import hello.core.member.MemberServiceImpl;

import java.util.Arrays;

public class MemberApp {
    public static void main(String[] args) {
        MemberService memberService = new MemberServiceImpl();
        Member member1 = new Member(1L, "member1", Grade.VIP);
        memberService.join(member1);

        Member findMember = memberService.findMember(member1.getId());
        System.out.println("findMember = " + findMember.getName());
        System.out.println("member1 = " + member1.getName());
    }
}

Join에 이용했던 member이름과, 회원조회를 통해 가져온 member객체의 이름이 같다. (그럴수밖...에)

테스트 케이스도 만들어보자.

테스트는 src밑에 main과 동일 선상에 자동으로 package 폴더가 만들어져 위치해 있다.

그 밑에 member / MemberServiceTest 라는 이름으로 클래스를 만들자

package hello.core.member;

import org.assertj.core.api.Assertions;
import org.junit.jupiter.api.Test;

public class MemberServiceTest {
    MemberService memberService = new MemberServiceImpl();
    @Test
    void join(){
        //given
        Member member =new Member(1L,"Member1",Grade.VIP);
        //when
        memberService.join(member);
        Member member1 = memberService.findMember(1L);
        //then
        Assertions.assertThat(member).isEqualTo(member1);

    }
}

Spring 테스트에서 Assertions을 자주 이용하므로 추가 학습후 테스트 주도개발에 잘 사용해야 한다.

문제 없이 정상 수행이 테스트 되었다.

앞으로 모든 도메인 개발에서 테스트 클래스는 필수적으로 작성할 것이다. 

어떤 방식으로 테스트를 작성하고 수행시키는것이 보다 현명하고 객체 지향적인 것인지도 잘 익히자. 

 

 

소스코드 ↓