ํ‹ฐ์Šคํ† ๋ฆฌ ๋ทฐ

๐Ÿ’ก๋น„์ฆˆ๋‹ˆ์Šค ์š”๊ตฌ์‚ฌํ•ญ ์ •๋ฆฌ

๋ฐ์ดํ„ฐ: ํšŒ์›ID, ์ด๋ฆ„
๊ธฐ๋Šฅ: ํšŒ์› ๋“ฑ๋ก, ์กฐํšŒ
์•„์ง ๋ฐ์ดํ„ฐ ์ €์žฅ์†Œ๊ฐ€ ์„ ์ •๋˜์ง€ ์•Š์Œ(๊ฐ€์ƒ์˜ ์‹œ๋‚˜๋ฆฌ์˜ค) --> ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค๋กœ ํ• ์ง€ No SQL๋กœ ํ• ์ง€ ์ด๋Ÿฐ๊ฒŒ ์•„์ง ์•ˆ ์ •ํ•ด์ง„ ์ƒํ™ฉ

๐Ÿ’ป์›น ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜ ๊ณ„์ธต ๊ตฌ์กฐ

 ์ปจํŠธ๋กค๋Ÿฌ: ์›น MVC์˜ ์ปจํŠธ๋กค๋Ÿฌ ์—ญํ• ๊ณผ API๋ฅผ ๋งŒ๋“œ๋Š” ์ปจํŠธ๋กค๋Ÿฌ ์—ญํ• ์„ ํ•œ๋‹ค.
์„œ๋น„์Šค: ํ•ต์‹ฌ ๋น„์ฆˆ๋‹ˆ์Šค ๋กœ์ง์ด ๋“ค์–ด๊ฐ€ ์žˆ์–ด, ํšŒ์›์€ ์ค‘๋ณต ๊ฐ€์ž…์ด ์•ˆ๋œ๋‹ค ๋“ฑ์˜ ๋Œ€ํ•œ ๋กœ์ง๋“ค์ด๋‹ค.
๋„๋ฉ”์ธ: ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค์— ์ฃผ๋กœ ์ €์žฅํ•˜๊ณ  ๊ด€๋ฆฌ๋˜๋Š” ๋น„์ฆˆ๋‹ˆ์Šค ๋„๋ฉ”์ธ ๊ฐ์ฒด์ด๋‹ค.
๋ฆฌํฌ์ง€ํ† ๋ฆฌ: ๋น„์ฆˆ๋‹ˆ์Šค ๋„๋ฉ”์ธ ๊ฐ์ฒด๋ฅผ ๊ฐ€์ง€๊ณ  ํ•ต์‹ฌ ๋น„์ฆˆ๋‹ˆ์Šค๊ฐ€ ๋™์ž‘ํ•˜๋„๋ก ๊ตฌํ˜„ํ•œ ๊ฐ์ฒด์ด๋‹ค. ๋„๋ฉ”์ธ ๊ฐ์ฒด๋ฅผ DB์— ์ €์žฅํ•˜๊ณ  ๊ด€๋ฆฌ
 
์ผ๋ฐ˜์ ์ธ ๊ณ„์ธตํ˜• ๊ตฌ์กฐ๋ฅผ ๋”ฐ๋ผ๊ฐ„๋‹ค.
 

๐Ÿ’ปํด๋ž˜์Šค ์˜์กด๊ด€๊ณ„

ํšŒ์›๋น„์ฆˆ๋‹ˆ์Šค ๋กœ์ง์—๋Š” ํšŒ์›์„œ๋น„์Šค(MemberService)๊ฐ€ ์žˆ๊ณ , ํšŒ์› ๋ฆฌํฌ์ง€ํ† ๋ฆฌ ํšŒ์›์„ ์ €์žฅํ•˜๋Š” ๊ฒƒ์€ ์ธํ„ฐํŽ˜์ด์Šค๋กœ ์„ค๊ณ„๋ฅผ ํ•  ๊ฒƒ์ด๋‹ค. ์•„์ง ๋ฐ์ดํ„ฐ ์ €์žฅ์†Œ๊ฐ€ ์„ ์ •๋˜์ง€ ์•Š์•˜๊ธฐ ๋•Œ๋ฌธ์—, ์šฐ์„  ๊ฐ„๋‹จํ•˜๊ฒŒ ๋ฉ”๋ชจ๋ฆฌ๋ฅผ ์ €์žฅ์„ ํ•œ ํ›„์—, ๋‚˜์ค‘์— ๋ฐ์ดํ„ฐ ์ €์žฅ์†Œ (DB)๊ฐ€ ์„ ์ •๋˜๋ฉด ๋ฉ”๋ชจ๋ฆฌ์— ์ €์žฅ๋œ ๋ฐ์ดํ„ฐ๋ฅผ DB๋กœ ๋ฐ”๊ฟ”์ฃผ์–ด์•ผ ํ•˜๊ธฐ ๋•Œ๋ฌธ์— ์ธํ„ฐํŽ˜์ด์Šค(interface)๋กœ ์„ค๊ณ„ํ•œ๋‹ค.
 

๐Ÿ’กํšŒ์› ๋„๋ฉ”์ธ๊ณผ ๋ฆฌํฌ์ง€ํ† ๋ฆฌ ๋งŒ๋“ค๊ธฐ

๐Ÿ’ป ํšŒ์› ๊ฐ์ฒด

main/java/hello.hellospring ํด๋”์— domain ํŒจํ‚ค์ง€ ์ถ”๊ฐ€, ๊ทธ ์•ˆ์— Member๋ผ๋Š” ํด๋ž˜์Šค๋ฅผ ๋งŒ๋“ค์–ด์ฃผ์—ˆ๋‹ค.

package hello.hellospring.domain;

public class Member {

    private Long id; //์ž„์˜์˜ ๊ฐ’, ๊ณ ๊ฐ์ด ์ €์žฅํ•˜๋Š” ๊ฒƒ์ด ์•„๋‹ˆ๋ผ ์‹œ์Šคํ…œ์ด ์ €์žฅํ•˜๋Š” ๊ฐ’
    private String name;

    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;
    }
}

ํšŒ์› ID์™€ ์ด๋ฆ„์— ๋Œ€ํ•œ getter setter๋ฅผ ๋งŒ๋“ค์–ด์ฃผ์—ˆ๋‹ค.
 

๐Ÿ’ป ํšŒ์› ๋ฆฌํฌ์ง€ํ† ๋ฆฌ ์ธํ„ฐํŽ˜์ด์Šค

์œ„ ๊ฒฝ๋กœ์— repository ํŒจํ‚ค์ง€์™€ MemberRepository ์ธํ„ฐํŽ˜์ด์Šค๋ฅผ ๋งŒ๋“ค์–ด์ค€๋‹ค.
์ธํ„ฐํŽ˜์ด์Šค๋Š” DB์—ฐ๊ฒฐ์„ ์œ„ํ•œ ๊ฒƒ์ด๋‹ค.
 

package hello.hellospring.repository;

import hello.hellospring.domain.Member;

import java.util.List;
import java.util.Optional;

public interface MemberRepository {
    Member save(Member member); //ํšŒ์›์ด ์ €์žฅ๋จ
    //์ฒซ ๋ฒˆ์งธ Member๋Š” ๋ฉ”์„œ๋“œ์˜ ๋ฐ˜ํ™˜ ํƒ€์ž…์„ ๋‚˜ํƒ€๋‚ด๋ฉฐ, ์ด ๊ฒฝ์šฐ save ๋ฉ”์„œ๋“œ๊ฐ€ ํ˜ธ์ถœ๋˜๋ฉด Member ๊ฐ์ฒด๋ฅผ ๋ฐ˜ํ™˜ํ•ฉ๋‹ˆ๋‹ค.
    // ๋‘ ๋ฒˆ์งธ Member๋Š” ๋ฉ”์„œ๋“œ์˜ ๋งค๊ฐœ๋ณ€์ˆ˜ ํƒ€์ž…์„ ๋‚˜ํƒ€๋‚ด๋ฉฐ, member๋ผ๋Š” ์ด๋ฆ„์˜ Member ๊ฐ์ฒด๋ฅผ ๋งค๊ฐœ๋ณ€์ˆ˜๋กœ ๋ฐ›์•„ ๋ฉ”์„œ๋“œ๋ฅผ ํ˜ธ์ถœํ•  ์ˆ˜ ์žˆ์Œ์„ ์˜๋ฏธ
    Optional<Member> findById(Long id); //findById, findByName์œผ๋กœ ๊ฐ€์ ธ์˜ค๋Š” ๊ฐ’์ด null์ผ ์ˆ˜ ์žˆ์Œ.
    //์š”์ฆ˜์—๋Š” null์„ ์ฒ˜๋ฆฌํ•˜๋Š” ๋ฐฉ๋ฒ•์—์„œ null์„ ๊ทธ๋Œ€๋กœ ๋ฐ˜ํ™˜ํ•˜๋Š” ๋ฐฉ๋ฒ• ๋Œ€์‹  Optional ์ด๋ผ๋Š” ๊ฑธ๋กœ ๊ฐ์‹ธ์„œ ๋ฐ˜ํ™˜ํ•˜๋Š” ๋ฐฉ๋ฒ•์„ ๋งŽ์ด ์„ ํ˜ธ
    Optional<Member> findByName(String name);
    List<Member> findAll(); //์ง€๊ธˆ๊นŒ์ง€ ์ €์žฅ๋œ ๋ชจ๋“  ํšŒ์›๋“ค์˜ ๋ฆฌ์ŠคํŠธ๋ฅผ ๋ฐ˜ํ™˜

 
์š”์ฆ˜์—๋Š” null์„ ์ฒ˜๋ฆฌํ•˜๋Š” ๋ฐฉ๋ฒ•์—์„œ null์„ ๊ทธ๋Œ€๋กœ ๋ฐ˜ํ™˜ํ•˜๋Š” ๋ฐฉ๋ฒ• ๋Œ€์‹  Optional ์ด๋ผ๋Š” ๊ฑธ๋กœ ๊ฐ์‹ธ์„œ ๋ฐ˜ํ™˜ํ•˜๋Š” ๋ฐฉ๋ฒ•์„ ๋งŽ์ด ์„ ํ˜ธํ•œ๋‹ค๊ณ  ํ•œ๋‹ค.
 

๐Ÿ’ป ํšŒ์› ๋ฆฌํฌ์ง€ํ† ๋ฆฌ ๋ฉ”๋ชจ๋ฆฌ ๊ตฌํ˜„์ฒด

์œ„์—์„œ ๋งŒ๋“ค์—ˆ๋˜ MemberRepository ์ธํ„ฐํŽ˜์ด์Šค๊ฐ€ ์žˆ๋Š” repository ํŒจํ‚ค์ง€ ์•ˆ์— MemoryMemberRepository ํด๋ž˜์Šค๋ฅผ ๋งŒ๋“ค์–ด์ค€๋‹ค. ์—ฌ๊ธฐ์„  MemberRepository interface๋ฅผ ๊ตฌํ˜„ํ•˜๊ธฐ ์œ„ํ•œ implements ๋ฉ”์„œ๋“œ๋ฅผ ์ƒ์„ฑํ•  ๊ฒƒ์ด๋‹ค.
 

package hello.hellospring.repository;

import hello.hellospring.domain.Member;

import java.util.*;

public class MemoryMemberRepository implements MemberRepository{

    private static Map<Long, Member> store = new HashMap<>();
    //Long ํƒ€์ž…์˜ ํ‚ค์™€ Member ๊ฐ์ฒด๋ฅผ ๊ฐ’์œผ๋กœ ๊ฐ€์ง€๋Š” HashMap ๊ฐ์ฒด๋กœ ์ดˆ๊ธฐํ™”
    private static long sequence = 0L;

    @Override
    public Member save(Member member) {
        member.setId(++sequence);
        store.put(member.getId(), member);
        //member ๊ฐ์ฒด์˜ id๋ฅผ ํ‚ค๋กœ ์‚ฌ์šฉํ•˜๊ณ , member ๊ฐ์ฒด ์ž์ฒด๋ฅผ ๊ฐ’์œผ๋กœ ์ €์žฅํ•ฉ๋‹ˆ๋‹ค.
        // ์ด๋ ‡๊ฒŒ ํ•˜๋ฉด id๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ํšŒ์›์„ ์กฐํšŒํ•  ์ˆ˜ ์žˆ๊ฒŒ ๋ฉ๋‹ˆ๋‹ค.
        return member;
    }

    @Override
    public Optional<Member> findById(Long id) {
        return Optional.ofNullable(store.get(id)); //null์ด์–ด๋„ ๊ฐ์Œ€ ์ˆ˜ ์žˆ์Œ
    }

    @Override
    public Optional<Member> findByName(String name) {
        return store.values().stream()
                .filter(member -> member.getName().equals(name))
                .findAny();
    }
    //์ŠคํŠธ๋ฆผ์„ ํ†ตํ•ด ๋งต์— ์ €์žฅ๋œ ๋ชจ๋“  Member ๊ฐ์ฒด์— ์ ‘๊ทผ
    //์ŠคํŠธ๋ฆผ์˜ filter ๋ฉ”์„œ๋“œ๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ์กฐ๊ฑด์„ ๋งŒ์กฑํ•˜๋Š” ์š”์†Œ๋งŒ ๋‚จ๊น๋‹ˆ๋‹ค. ์—ฌ๊ธฐ์„œ๋Š” ํšŒ์›์˜ ์ด๋ฆ„์ด ์ฃผ์–ด์ง„ name๊ณผ ๋™์ผํ•œ ๊ฒฝ์šฐ๋งŒ์„ ํ•„ํ„ฐ๋ง
    //Optional๋กœ 'name'๊ณผ ์ผ์น˜ํ•˜๋Š” ํšŒ์›์„ ๋ชป์ฐพ์•˜์„ ๋•Œ์—” ๋นˆ 'Optional'๋ฐ˜ํ™˜
    //.findAny(): ํ•„ํ„ฐ๋ง๋œ ์š”์†Œ ์ค‘ ํ•˜๋‚˜๋ฅผ ์ฐพ์Œ

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

์ฝ”๋“œ ์ฃผ์„์„ ์ฐธ๊ณ ํ•ด์ฃผ๊ธธ ๋ฐ”๋ž€๋‹ค.
 

๐Ÿ’กํšŒ์› ๋ฆฌํฌ์ง€ํ† ๋ฆฌ ํ…Œ์ŠคํŠธ ์ผ€์ด์Šค ์ž‘์„ฑ

์œ„์—์„œ ๋งŒ๋“  MemoryMemberRepository๊ฐ€ ์ •์ƒ์ ์œผ๋กœ ์ž˜ ๋Œ์•„๊ฐ€๋Š”์ง€ ๊ฒ€์ฆํ•˜๊ธฐ ์œ„ํ•ด ํ…Œ์ŠคํŠธ ์ผ€์ด์Šค๋ฅผ ์ž‘์„ฑํ•œ๋‹ค.
์ž๋ฐ”์˜ JUnit์ด๋ผ๋Š” ํ”„๋ ˆ์ž„์›Œํฌ๋กœ ํ…Œ์ŠคํŠธ๋ฅผ ์‹คํ–‰ํ•œ๋‹ค.

์œ„ ๊ฒฝ๋กœ์— repositoryํŒจํ‚ค์ง€์™€ MemoryMemberRepositoryTest ํด๋ž˜์Šค๋ฅผ ๋งŒ๋“ค์–ด์ค€๋‹ค.

package hello.hellospring.repository;

import hello.hellospring.domain.Member;
import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.Test;

import java.util.List;

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

class MemoryMemberRepositoryTest { // ๊ตณ์ด public ์œผ๋กœ ํ•  ํ•„์š”์—†์–ด์„œ ์ง€์›€

    // Test๋ฅผ ํ•˜๊ธฐ ์œ„ํ•œ ์ €์žฅ์†Œ
    MemoryMemberRepository repository = new MemoryMemberRepository();

    @AfterEach
    public void afterEach(){
        repository.clearStore();
    }

    @Test
    public void save(){
        Member member = new Member();
        member.setName("spring");

        repository.save(member);

        Member result = repository.findById(member.getId()).get();
        //Assertions.assertEquals(member, result); //๊ธฐ๋Œ€ํ•˜๋Š” ๊ฒƒ(expected), actual ์ˆœ
        //result๋ž‘ member๋ž‘ ๋˜‘๊ฐ™์€์ง€ ํ™•์ธํ•ด ๋ณผ ์ˆ˜ ์žˆ์Œ
        assertThat(member).isEqualTo(result);
    }

    @Test
    public void findByName(){
        Member member1 = new Member();
        member1.setName("spring1");
        repository.save(member1);

        Member member2 = new Member();
        member2.setName("spring2");
        repository.save(member2);

        Member result = repository.findByName("spring1").get();

        assertThat(member1).isEqualTo(result);
    }

    @Test
    public void findAll(){
        Member member1 = new Member();
        member1.setName("spring1");
        repository.save(member1);

        Member member2 = new Member();
        member2.setName("spring2");
        repository.save(member2);

        List<Member> result = repository.findAll();

        assertThat(result.size()).isEqualTo(2);
    }
}

๊ฐ์ž ๋ฉ”์„œ๋“œ๊ฐ€ ์ •์ƒ์ ์œผ๋กœ ์ž‘๋™์ด ๋˜๋Š”์ง€ ํ™•์ธํ•˜๊ธฐ ์œ„ํ•ด save, findByName, findAll Test ์ฝ”๋“œ๋ฅผ ์ž‘์„ฑํ•ด์ฃผ์—ˆ๋‹ค.

๋ชจ๋“  ๋ฉ”์†Œ๋“œ๋“ค์— ๋Œ€ํ•ด Test๋ฅผ ํ•œ๊บผ๋ฒˆ์— ์‹คํ–‰ํ•˜๊ณ  ์‹ถ๋‹ค๋ฉด class ์˜†์— run ๋ฒ„ํŠผ์„ ๋ˆ„๋ฅด๊ฑฐ๋‚˜,

hello.hellospring์— ๋Œ€ํ•ด Run์„ ๋Œ๋ ค์ฃผ๋ฉด ๋œ๋‹ค.
 
์œ„์— ์žˆ๋Š” AfterEach๋Š” ๋งค์šฐ ์ค‘์š”ํ•œ๋ฐ, ๋งŒ์•ฝ AfterEach๊ฐ€ ์—†๋‹ค๋ฉด 

run์„ ํ–ˆ์„ ๋•Œ ์œ„์™€๊ฐ™์€ ์—๋Ÿฌ๊ฐ€ ๋ฐœ์ƒํ•œ๋‹ค.
์ด๋Š” findAll๊ณผ findByName์—์„œ ๋ชจ๋‘ ๋˜‘๊ฐ™์€ member1๊ณผ member2 ๊ฐ์ฒด๊ฐ€ ๋‘˜ ๋‹ค ์ƒ์„ฑ ๋˜์—ˆ๊ธฐ ๋•Œ๋ฌธ์—, ๋ฌด์—‡์ด ๋จผ์ € ์‹คํ–‰๋˜์—ˆ๋ƒ์— ๋”ฐ๋ผ ์—๋Ÿฌ๊ฐ€ ๋ฐœ์ƒํ•œ๋‹ค.
 
ํ•˜์ง€๋งŒ AfterEach๋ฉ”์„œ๋“œ๋ฅผ ๋งŒ๋“ค์–ด์ฃผ๋ฉด, ๋ฉ”์„œ๋“œ ์‹คํ–‰์ด ๋๋‚  ๋•Œ๋งˆ๋‹ค ์ €์žฅ์†Œ์˜ ๋‚ด์šฉ๋“ค์„ ๋ชจ๋‘ ์‚ญ์ œํ•ด์ค„ ์ˆ˜ ์žˆ๋‹ค.

@AfterEach
    public void afterEach(){
        repository.clearStore();
    }

-> Test์— ์žˆ๋Š” MemoryMemberRepository์—์„œ.

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

-> main์— ์žˆ๋Š” MemoryMemberRepository์—์„œ.
 
ํ…Œ์ŠคํŠธ ํด๋ž˜์Šค๋ฅผ ๋จผ์ € ์ž‘์„ฑํ•œ ๋‹ค์Œ์— ๋ฉค๋ฒ„ ๋ฆฌํฌ์ง€ํ† ๋ฆฌ๋ฅผ ์ž‘์„ฑํ•  ์ˆ˜๋„ ์žˆ๋‹ค.
TDD(ํ…Œ์ŠคํŠธ ์ฃผ๋„ ๊ฐœ๋ฐœ): ํ‹€์„ ๋จผ์ € ๋งŒ๋“œ๋Š” ๊ฒƒ์œผ๋กœ, ํ…Œ์ŠคํŠธ๋ฅผ ๋จผ์ € ๋งŒ๋“ค๊ณ  ๊ตฌํ˜• ํด๋ž˜์Šค๋ฅผ ๋งŒ๋“ค์–ด์„œ ๋Œ๋ ค๋ณด๋Š” ๊ฒƒ์„ ์˜๋ฏธํ•œ๋‹ค.
 

๐Ÿ’กํšŒ์› ์„œ๋น„์Šค ๊ฐœ๋ฐœ

ํšŒ์› ์„œ๋น„์Šค๋Š” ์ด์ „์— ๋งŒ๋“ค์—ˆ๋˜ ํšŒ์› domain๊ณผ repository๋ฅผ ํ™œ์šฉํ•˜์—ฌ ์‹ค์ œ ๋น„์ฆˆ๋‹ˆ์Šค ๋กœ์ง์„ ์ž‘์„ฑํ•˜๋Š” ๊ฒƒ์ด๋‹ค.

์œ„์™€ ๊ฐ™์€ ๊ฒฝ๋กœ์— service๋ผ๋Š” ํŒจํ‚ค์ง€์™€ MemberService๋ผ๋Š” class๋ฅผ ๋งŒ๋“ค์–ด์ฃผ์—ˆ๋‹ค.

package hello.hellospring.service;

import hello.hellospring.domain.Member;
import hello.hellospring.repository.MemberRepository;
import hello.hellospring.repository.MemoryMemberRepository;

import java.util.List;
import java.util.Optional;

public class MemberService {

    private final MemberRepository memberRepository = new MemoryMemberRepository();

    /**
     * ํšŒ์› ๊ฐ€์ž…
     */
    public Long join(Member member) {
        //๊ฐ™์€ ์ด๋ฆ„์ด ์žˆ๋Š” ์ค‘๋ณต ํšŒ์›X
//        Optional<Member> result = memberRepository.findByName(member.getName());
//        result.ifPresent(m -> {
//            throw new IllegalStateException("์ด๋ฏธ ์กด์žฌํ•˜๋Š” ํšŒ์›์ž…๋‹ˆ๋‹ค.");
//        });

        validateDuplicateMember(member); //์ค‘๋ณต ํšŒ์› ๊ฒ€์ฆ
        memberRepository.save(member);
        return member.getId();
    }

    private void validateDuplicateMember(Member member) {
        memberRepository.findByName(member.getName())
            .ifPresent(m -> {
                throw new IllegalStateException("์ด๋ฏธ ์กด์žฌํ•˜๋Š” ํšŒ์›์ž…๋‹ˆ๋‹ค.");
            });
    }

    /**
     * ์ „์ฒด ํšŒ์› ์กฐํšŒ
     */
    public List<Member> findMembers(){
        return memberRepository.findAll();
    }

    public Optional<Member> findOne(Long memberId) {
        return memberRepository.findById(memberId);
    }


}

join ๋ฉ”์„œ๋“œ๋ฅผ ์ž‘์„ฑํ•˜๋ฉด์„œ, ์ค‘๋ณต ํšŒ์› ๊ฒ€์ฆ์„ ํ•˜๋Š” ๋ฉ”์„œ๋“œ๋ฅผ ์ƒˆ๋กœ ๋งŒ๋“ค์–ด ์ฃผ์—ˆ๊ณ ,
์ด์–ด์„œ ์ „์ฒด ํšŒ์›์„ ์กฐํšŒํ•˜๋Š” findMembers๋ฉ”์„œ๋“œ์™€
id๋กœ ํšŒ์›์„ ์กฐํšŒํ•˜๋Š” findOne๋ฉ”์„œ๋“œ๋ฅผ ๋งŒ๋“ค์–ด์ฃผ์—ˆ๋‹ค.
 

๐Ÿ’กํšŒ์› ์„œ๋น„์Šค ํ…Œ์ŠคํŠธ

MemberService ํŒŒ์ผ์—์„œ Generate -> Test๋ฅผ ๋ˆ„๋ฅด๋ฉด

์œ„ ๊ฒฝ๋กœ์— ์ž๋™์œผ๋กœ MemberServiceTest๊ฐ€ ์ƒ๊ธด๋‹ค.

package hello.hellospring.service;

import org.junit.jupiter.api.Test;

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

class MemberServiceTest {

    @Test
    void join() {
    }

    @Test
    void findMembers() {
    }

    @Test
    void findOne() {
    }
}

-> ์œ„์™€ ๊ฐ™์€ ์ฝ”๋“œ๋“ค์ด ์ž๋™์œผ๋กœ ์ƒ์„ฑ
 

package hello.hellospring.service;

import hello.hellospring.domain.Member;
import hello.hellospring.repository.MemoryMemberRepository;
import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.Test;

import java.util.Optional;

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

class MemberServiceTest {

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

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

    @Test
    void ํšŒ์›๊ฐ€์ž…() {
        //given
        Member member = new Member();
        member.setName("spring");

        //when
        Long saveId = memberService.join(member);

        //then
        Member findMember = memberService.findOne(saveId).get();
        //memberRepository์—์„œ ๊ฐ€์ ธ์™€์„œ ๋น„๊ตํ•ด์•ผ๋˜๋‹ˆ๊นŒ ๊ฐ„๋‹จํ•œ findOne์œผ๋กœ ๊ฐ์ฒด ๊ฐ€์ ธ์˜ด
        // ํšŒ์›๊ฐ€์ž…ํ•œ member์˜ id๊ฐ€ ์ €์žฅ์†Œ์— ์žˆ์œผ๋ฉด, ํ•ด๋‹น member ๊ฐ์ฒด๋ฅผ findMember๋กœ
        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);
//        try{
//            memberService.join(member2); //validate์—์„œ ๊ฑธ๋ ค์„œ ์˜ˆ์™ธ๊ฐ€ ํ„ฐ์ง
//            fail();
//        } catch (IllegalStateException e){
//            assertThat(e.getMessage()).isEqualTo("์ด๋ฏธ ์กด์žฌํ•˜๋Š” ํšŒ์›์ž…๋‹ˆ๋‹ค.");
//        }
        //try catch๋ฌธ์€ ๋ฒˆ๊ฑฐ๋กœ์›€

        IllegalStateException e = assertThrows(IllegalStateException.class, () -> memberService.join(member2));

        assertThat(e.getMessage()).isEqualTo("์ด๋ฏธ ์กด์žฌํ•˜๋Š” ํšŒ์›์ž…๋‹ˆ๋‹ค.");
        //then
        
    }

    @Test
    void findMembers() {
    }

    @Test
    void findOne() {
    }
}

ํšŒ์›๊ฐ€์ž… test ์ฝ”๋“œ์™€ ์ค‘๋ณต ํšŒ์› ์˜ˆ์™ธ test์ฝ”๋“œ๋„ ์ž‘์„ฑํ•ด์ฃผ์—ˆ๋‹ค.
์ €์žฅ์†Œ์— ์ค‘๋ณต๋œ ํšŒ์›์ด ์žˆ์„ ๊ฒฝ์šฐ ์œ„ ์ฝ”๋“œ์— ๋”ฐ๋ผ ์ •์ƒ์ ์œผ๋กœ ์˜ˆ์™ธ ์ฒ˜๋ฆฌ๊ฐ€ ๋œ๋‹ค.
 

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

@AfterEach // ๋ฉ”์„œ๋“œ ์‹คํ–‰์ด ๋๋‚  ๋•Œ๋งˆ๋‹ค ์‹คํ–‰๋จ
public void afterEach() {
	memberRepository.clearStore(); // ์ €์žฅ์†Œ ๋‚ด์šฉ ๋‹ค ์ง€์›€
}

์ด๋ฒˆ์—๋„ ์ €๋ฒˆ์ฒ˜๋Ÿผ ๊ฐ ๋ฉ”์„œ๋“œ์˜ ์‹คํ–‰์ด ๋๋‚  ๋•Œ๋งˆ๋‹ค ์ €์žฅ์†Œ์— ์žˆ๋Š” ๋‚ด์šฉ์„ ์ง€์›Œ์ค€๋‹ค.
 
๐Ÿšจ ๐Ÿšจ ๐Ÿšจ ๊ทธ๋Ÿฌ๋‚˜ ํšŒ์› ๋ฆฌํฌ์ง€ํ† ๋ฆฌ ํ…Œ์ŠคํŠธ ์ผ€์ด์Šค ์ฒ˜๋Ÿผ memberRepository์˜ ๋‚ด์šฉ์„ ์ง€์šฐ๋ฉด ๋ฌธ์ œ๊ฐ€ ๋ฐœ์ƒํ•  ์ˆ˜ ์žˆ๋‹ค.
์™œ๋ƒํ•˜๋ฉด memberService ๊ฐ์ฒด๊ฐ€ ์•„๋‹Œ ์ƒˆ๋กœ์šด memberRepository ์ €์žฅ์†Œ ๊ฐ์ฒด๋ฅผ ๋งŒ๋“ค์—ˆ๊ธฐ ๋•Œ๋ฌธ์ด๋‹ค. ๊ทธ๋ž˜์„œ ๋‹ค๋ฅธ ๋‚ด์šฉ์„ ์ง€์šธ ์ˆ˜ ์žˆ๋Š” ์œ„ํ—˜์ด ์žˆ๊ธฐ ๋•Œ๋ฌธ์— ์œ„์— ๋ฐฉ๋ฒ•์ด ์•„๋‹Œ ๋‹ค๋ฅธ ๋ฐฉ๋ฒ•์œผ๋กœ clearStore() ๋ฅผ ํ•ด์•ผํ•œ๋‹ค.
์ง€๊ธˆ์€ MemoryMemberRepository ์ €์žฅ์†Œ๊ฐ€ static์ด๋ผ์„œ ๋ฌธ์ œ๋Š” ์—†์ง€๋งŒ, ํ˜น์‹œ๋ผ๋„ static์ด ์•„๋‹Œ ๊ฒฝ์šฐ ์„œ๋น„์Šค์˜ ์ €์žฅ์†Œ๊ฐ€ ์•„๋‹Œ ๋‹ค๋ฅธ ์ €์žฅ์†Œ๋ฅผ ์ฒ˜๋ฆฌํ•˜๊ฒŒ ๋˜๋Š” ๋ฌธ์ œ๊ฐ€ ๋ฐœ์ƒํ•˜๊ฒŒ ๋œ๋‹ค. (์ถœ์ฒ˜: easylog)

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

 
 

๐Ÿ’กํšŒ์› ์„œ๋น„์Šค ํ…Œ์ŠคํŠธ - clearStore, DI

์œ„์™€ ๊ฐ™์€ ๋ฌธ์ œ๋ฅผ ํ•ด๊ฒฐํ•˜๊ธฐ ์œ„ํ•ด์„  MemberService์— memberRepository๋ฅผ ์™ธ๋ถ€์—์„œ ๋„ฃ์–ด์ฃผ๋„๋ก ๋ณ€๊ฒฝํ•˜๋ฉด ๋œ๋‹ค.
 
src/main/java/hello.hellospring/service/MemberService ํŒŒ์ผ์—์„œ์˜ ์ˆ˜์ •

private final MemberRepository memberRepository;
    
public MemberService(MemberRepository memberRepository) {
	this.memberRepository = memberRepository;
}

 
src/test/java/hello.hellospring/service/MemberServiceTest ํŒŒ์ผ์—์„œ์˜ ์ˆ˜์ •

MemberService memberService;
MemoryMemberRepository memberRepository;

@BeforeEach // ๋ฉ”์„œ๋“œ ์‹œ์ž‘๋˜๊ธฐ ์ „
public void beforeEach() {
	memberRepository = new MemoryMemberRepository();
	memberService = new MemberService(memberRepository);
}

@AfterEach // ๋ฉ”์„œ๋“œ ์‹œ์ž‘๋œ ํ›„
public void afterEach() {
	memberRepository.clearStore();
}

 
์ด๋Ÿฌ๋ฉด ์ด์ œ ๊ฐ™์€ memberRepository๊ฐ€ ์ƒ์„ฑ์ด ๋˜๊ณ , ๋ฉ”์„œ๋“œ๊ฐ€ ๋๋‚˜๋ฉด memberRepository๋ฅผ clear ํ•˜๊ฒŒ ๋œ๋‹ค.
์ด๋ฅผ DI(Dependency Injection)์ด๋ผ๊ณ  ํ•œ๋‹ค.

'Spring' ์นดํ…Œ๊ณ ๋ฆฌ์˜ ๋‹ค๋ฅธ ๊ธ€

[SPRING]์Šคํ”„๋ง ์ž…๋ฌธ - ์ฝ”๋“œ๋กœ ๋ฐฐ์šฐ๋Š” ์Šคํ”„๋ง ๋ถ€ํŠธ, ์›น MVC, DB ์ ‘๊ทผ ๊ธฐ์ˆ  ์„น์…˜6 (์Šคํ”„๋ง DB ์ ‘๊ทผ ๊ธฐ์ˆ )  (1) 2023.12.29
[SPRING]์Šคํ”„๋ง ์ž…๋ฌธ - ์ฝ”๋“œ๋กœ ๋ฐฐ์šฐ๋Š” ์Šคํ”„๋ง ๋ถ€ํŠธ, ์›น MVC, DB ์ ‘๊ทผ ๊ธฐ์ˆ  ์„น์…˜5 (ํšŒ์› ๊ด€๋ฆฌ ์˜ˆ์ œ - ์›น MVC ๊ฐœ๋ฐœ)  (1) 2023.12.24
[SPRING]์Šคํ”„๋ง ์ž…๋ฌธ - ์ฝ”๋“œ๋กœ ๋ฐฐ์šฐ๋Š” ์Šคํ”„๋ง ๋ถ€ํŠธ, ์›น MVC, DB ์ ‘๊ทผ ๊ธฐ์ˆ  ์„น์…˜4 (์Šคํ”„๋ง ๋นˆ๊ณผ ์˜์กด๊ด€๊ณ„)  (0) 2023.11.27
[SPRING]์Šคํ”„๋ง ์ž…๋ฌธ - ์ฝ”๋“œ๋กœ ๋ฐฐ์šฐ๋Š” ์Šคํ”„๋ง ๋ถ€ํŠธ, ์›น MVC, DB ์ ‘๊ทผ ๊ธฐ์ˆ  ์„น์…˜ 2 (์ •์ ์ปจํ…์ธ , MVC์™€ ํ…œํ”Œ๋ฆฟ ์—”์ง„, API)  (1) 2023.11.07
[SPRING]์Šคํ”„๋ง ์ž…๋ฌธ - ์ฝ”๋“œ๋กœ ๋ฐฐ์šฐ๋Š” ์Šคํ”„๋ง ๋ถ€ํŠธ, ์›น MVC, DB ์ ‘๊ทผ ๊ธฐ์ˆ  ์„น์…˜ 0~1 (ํ”„๋กœ์ ํŠธ ์ƒ์„ฑ, ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ ์‚ดํŽด๋ณด๊ธฐ, Viewํ™˜๊ฒฝ์„ค์ •, ๋นŒ๋“œํ•˜๊ณ  ์‹คํ–‰ํ•˜๊ธฐ)  (0) 2023.11.07