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

[개발일지#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