본문 바로가기
💻 뚝딱뚝딱/(구) 북북클럽

[개발일지#001] 프로젝트 생성, User 도메인 생성 및 테스트

by 뚜루리 2024. 1. 10.
728x90
320x100
[참고]
김영한님 스프링 강의를 바탕으로 진행되는 토이프로젝트의 과정을 기록하는 글입니다. 
둥근 피드백은 언제나 환영입니다.
[오늘의 개발내용]
1. 스프링 프로젝트를 스프링 스타터를 이용해 생성
2. 유저 도메인 생성 (Member, MemberRepository)
3. 생성된 유저 도메인을 junit을 통해 테스트 해봄 (MemberRepositoryTest)

 

간단 요구사항 (Member)

회원 도메인

  • 아이디
  • 닉네임
  • 비밀번호

 

회원 관리기능

  • 회원가입
  • 회원상세
  • 회원수정
  • 탈퇴 (논리적 삭제)

 


 

1. 스프링 프로젝트를 스프링스타터를 이용해 생성

 

[인텔리제이/스프링] 스프링스타터로 스프링 프로젝트 생성하기

스프링 프로젝트를 만들 때 스프링스타터 사이트를 이용하면 간편하게 만들 수 있음. 1. 스프링 스타터 사이트 접속 https://start.spring.io/ 2. 아래와 같은 화면이 있을 텐데 만들 프로젝트의 설정을

ddururiiiiiii.tistory.com

 

2-1. 유저 도메인을 생성 (Member)

package toyproject.bookbookclub.domain.Members;

import lombok.Data;
import lombok.Getter;
import lombok.Setter;

@Getter @Setter
public class Member {

    private String id;
    private String NickName;
    private String password;

    public Member() {
    }

    public Member(String id, String nickName, String password) {
        this.id = id;
        NickName = nickName;
        this.password = password;
    }
}
  • 정말 정말 간단하게 아이디, 닉네임, 패스워드 필드만 사용하고 나중에 필요한 필드가 있다면 그 때 추가하든지 할 예정
  • 아무것도 들어있지 않은 기본생성자와 세 항목을 모두 포함한 생성자 두 개를 생성

 

@Data 어노테이션 대신 @Getter, @Setter 어노테이션만 쓴 이유

https://ddururiiiiiii.tistory.com/369

 

[Spring/스프링부트] @Data 사용을 지양하는 이유 (= 단점)

[오늘의 궁금증] @Data 는 여러 어노테이션을 한 번에 쓸 수 있는 유용한 어노테이션이지만 한 편으로는 @Data 사용을 지양하기도 한다 그 이유가 뭘까? @Data 어노테이션이란? @ToString, @Getter, @Setter, @

ddururiiiiiii.tistory.com

 

 

2-2. 유저 도메인을 생성 (MemberRepository)

package toyproject.bookbookclub.domain.Members;

import org.springframework.stereotype.Repository;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;

@Repository
public class MemberRepository {

    private static final Map<String, Member> store = new ConcurrentHashMap<>(); //static 사용

    public Member save(Member member){
        store.put(member.getId(), member);
        return member;
    }

    public Member findById(String id){
        return store.get(id);
    }

    public List<Member> findAll(){
        return new ArrayList<>(store.values());
    }

    public void update(String memberId, Member updateParam){
        Member findMember = findById(memberId);
        findMember.setPassword(updateParam.getPassword());
        findMember.setNickName(updateParam.getNickName());
    }

    public void clearStore(){
        store.clear();
    }

}

 

[@Repository 어노테이션은?]

  • 해당 클래스를 루트 컨테이너에 빈(Bean) 객체로 생성해주는 어노테이션

 

[hashMap 이 아닌 ConcurrentHashMap을 쓴 이유]

hashMap

  • 데이터를 저장할 때 키-값 쌍으로 저장하며, 키는 중복되지 않으며 null을 허용함.
  • 값은 중복되어도 상관없으며, null도 허용.
  • HashMap은 동기화가 되어있지 않기 때문에 멀티스레드 환경에서 사용할 때는 주의가 필요

 

ConcurrentHashMap

  • ConcurrentHashMap은 멀티스레드 환경에서 안전하게 사용할 수 있는 해시 테이블 구조.
  • HashMap과 비슷하지만, 동기화를 적용하는 대신 세분화된 락(lock)을 사용하여 성능을 향상시킴.

 

  • 멀티쓰레드 환경에서 더 안전하게 사용할 수 있는 ConcurrentHashMap 을 사용함. 

 

생성된 유저 도메인을 junit을 통해 테스트 해봄 (MemberRepositoryTest)

package toyproject.bookbookclub.domain.Members;

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

import java.util.List;

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

class MemberRepositoryTest {

    MemberRepository memberRepository = new MemberRepository();

    @AfterEach
    void afterEach(){
        memberRepository.clearStore();
    }

    @Test
    void save(){
        //given
        Member member = new Member("testid", "닉네임", "1234");

        //when
        Member savedMember = memberRepository.save(member);

        //then
        //assertion.assert
        //option + enter -> 단축
        Member findMember = memberRepository.findById(member.getId());
        assertThat(findMember).isEqualTo(savedMember);
    }

    @Test
    void findAll(){
        //given
        Member member1 = new Member("testid1", "닉네임1", "1234");
        Member member2 = new Member("testid2", "닉네임2", "5678");
        memberRepository.save(member1);
        memberRepository.save(member2);

        //when
        List<Member> result = memberRepository.findAll();

        //then
        Assertions.assertThat(result.size()).isEqualTo(2);
    }

    @Test
    void updateMember(){

        //given
        Member member = new Member("testid1", "닉네임1", "1234");

        Member savedMember = memberRepository.save(member);
        String memberId = savedMember.getId();

        //when
        Member updateParam = new Member("testid2", "닉네임2", "5678");
        memberRepository.update(memberId, updateParam);

        Member findId = memberRepository.findById(memberId);

        //then
        assertThat(findId.getId()).isEqualTo(updateParam.getId());
        assertThat(findId.getNickName()).isEqualTo(updateParam.getNickName());
        assertThat(findId.getPassword()).isEqualTo(updateParam.getPassword());


    }

}

 

(+) Test 쉽게 만드는 방법 : 테스트를 만들려는 클래스 화면에서 cmd + Shift + T를 누르면 테스트 클래스를 자동 생성해준다.

 

 

(+) Assertions 클래스를 사용할 때는 org.assertj.core.api 를 사용해야 함.

 

 

(+) option + enter -> Assertions 를 static import로 사용하여 보다 간결하게 입력 가능. 

 

 

(+) 테스트 돌리는 법

메소드 마다 테스트 돌려보려면 메소드 옆에 초록색 재생 버튼을 클릭하면됨.

 

테스트 성공일 경우 아래와 같이 아이콘이 초록색 체크로 변경

 

실패일 경우 아래와 같이 빨간색 느낌표로 변경

 

728x90
320x100

뚜루리님의
글이 좋았다면 응원을 보내주세요!