๐ณ ๋น์ฆ๋์ค ์๊ตฌ์ฌํญ ์ ๋ฆฌ
๋ฐ์ดํฐ
: ํ์ID, ์ด๋ฆ
๊ธฐ๋ฅ
: ํ์ ๋ฑ๋ก, ํ์ ์กฐํ
DB
: ์์ง ์ด๋ค DB๋ฅผ ์ฌ์ฉํ ์ง ์ ํด์ง์ง ์์ ๊ฐ์์ ์๋๋ฆฌ์ค
โช ๋ฐ๋ผ์ ์ธํฐํ์ด์ค๋ก ๊ตฌํ ํด๋์ค๋ฅผ ๋ณ๊ฒฝํ ์ ์๋๋ก ์ค๊ณ
→ ๊ตฌํ์ฒด๋ฅผ ํตํด ๊ฐ๋ฒผ์ด ๋ฉ๋ชจ๋ฆฌ ๊ธฐ๋ฐ์ ๋ฐ์ดํฐ ์ ์ฅ์ ์ฌ์ฉ
โช ํ ์คํธ ํ๋ ์์ํฌ → junit
์ผ๋ฐ์ ์ธ ์น ์ ํ๋ฆฌ์ผ์ด์ ๊ณ์ธต ๊ตฌ์กฐ
โช controller → ์น MVC์ ์ปจํธ๋กค๋ฌ ์ญํ
โช service → ํต์ฌ ๋น์ฆ๋์ค ๋ก์ง ๊ตฌํ
โช repository → ๋ฐ์ดํฐ๋ฒ ์ด์ค์ ์ง์ ์ ๊ทผ, ๋๋ฉ์ธ ๊ฐ์ฒด๋ฅผ DB์ ์ ์ฅํ๊ณ ๊ด๋ฆฌ
→ Node์์ ์ฌ์ฉํ๋ model๊ณผ ๋น์ทํ ์ญํ ์ด๋ผ๊ณ ์๊ฐํ๋ฉด ๋ ๋ฏ ํ๋ค
โช domain → ๋น์ฆ๋์ค ๋๋ฉ์ธ ๊ฐ์ฒด
→ ํ์, ์ฃผ๋ฌธ ๋ฑ๋ฑ ์ฃผ๋ก DB์ ์ ์ฅํ๊ณ ๊ด๋ฆฌ๋์ด์ง๋ ๊ฐ์ฒด
ํด๋์ค ์์กด๊ด๊ณ
๐ณ ํ์ ๋๋ฉ์ธ๊ณผ ๋ ํฌ์งํ ๋ฆฌ
→ ์ผ๋ฐ์ ๊ณ์ธตํ ๊ตฌ์กฐ๋๋ก ์์ฑ
ํ์ ๋๋ฉ์ธ ์์ฑ
main/domain/Member
public class Member {
private Long id; // ์์คํ
์์์ ์ ์ฅํ๋ 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;
}
}
๋ ํฌ์งํ ๋ฆฌ ์ธํฐํ์ด์ค ์์ฑ
main/repository/MemberRepository
public interface MemberRepository {
Member save(Member member);
Optional<Member> findById(Long id); // optional๊ธฐ๋ฅ ๊ณต๋ถ
Optional<Member> findByName(String name);
List<Member> findAll();
}
๋ ํฌ์งํ ๋ฆฌ์ 4๊ฐ์ง ๊ธฐ๋ฅ์ ๋ง๋ค์ด์ฃผ์๋ค.
ํ์ ๋ ํฌ์งํ ๋ฆฌ ๋ฉ๋ชจ๋ฆฌ ๊ตฌํ์ฒด
DB๊ฐ ์ ์ ๋์ง ์์์ผ๋ฏ๋ก ์ผ์์ ์ผ๋ก ์์ฑํ ํ์ ๋ฆฌํฌ์งํ ๋ฆฌ ๊ตฌํ์ฒด
main/repository/MemoryMemberRepository
@Repository
public class MemoryMemberRepository implements MemberRepository{
private static Map<Long, Member> store = new HashMap<>();
private static long sequence = 0L;
// ์ ์ฅ
@Override
public Member save(Member member) {
member.setId(++sequence); // id setting
store.put(member.getId(), member); // store
return member;
}
// id๋ก ์ฐพ๊ธฐ
@Override
public Optional<Member> findById(Long id) {
return Optional.ofNullable(store.get(id));
}
// name์ผ๋ก ์ฐพ๊ธฐ
@Override
public Optional<Member> findByName(String name) {
return store.values().stream()
.filter(member -> member.getName().equals(name))
.findAny();
}
// ๋ชจ๋ ์ฐพ๊ธฐ
@Override
public List<Member> findAll() {
// values <-> members
return new ArrayList<>(store.values());
}
// test์ฉ
public void clearStore(){
store.clear();
}
}
โช hashmap์ ์ฌ์ฉํ์ฌ ์ ์ฅ
→ ์ค๋ฌด์์๋ ๊ณต์ ๋๋ hashmap์ ์ฌ์ฉํ ๋ ๋์์ฑ ๋ฌธ์ ๋ฅผ ํด๊ฒฐํ๊ธฐ ์ํด concreteHashmap์ ์ฌ์ฉํ๋ค๊ณ ํ๋ค
โช Long ํ์ ์ผ๋ก ํค๊ฐ(pk) ์์ฑ
โช Optional.ofNullable
→ ๊ฐ์ด null์ธ์ง ์๋์ง ํ์ ํ ์ ์๋ ๊ฐ์ฒด๋ฅผ ๋ด๊ณ ์๋ Optional๊ฐ์ฒด ์์ฑ
→ ๊ฒฐ๊ณผ๊ฐ์ด null์ผ ์๋ ์๋ค๋ฉด Optional๋ก ๊ฐ์ธ์ฃผ์ด ์์ฑํด์ผ ํ๋ค
โช List<Member>
→ ์ค๋ฌด์์๋ List๋ฅผ ๋ง์ด ์ฌ์ฉํ๋ค๊ณ ํ๋ค
๐ณ ํ ์คํธ ์ผ์ด์ค ์์ฑ
โช ์ค๋ฌด์์ test code ์์ด๋ ์์ ์ด ๋ถ๊ฐ๋ฅํ ์ ๋๋ก ์ค์ํ๋ค๊ณ ํ๋คโญ
โช JUnit์ผ๋ก ํ ์คํธ๋ฅผ ์คํํ๋ฉฐ ๋ฒ๊ฑฐ๋ก์์ ์ค์ธ๋ค
โช JUnit : ์๋ฐ์ฉ ๋จ์ ํ ์คํธ ์์ฑ์ ์ํ ํ๋ ์์ํฌ
→ ๊ฐ์ ํจํค์ง ๋ด์ ํ ์คํธ ๋์ ํด๋์ค์ ํ ์คํธ ํด๋์ค๊ฐ ์์นํ๋๋ก ์ค๊ณํ๋ค
→ ๋ณดํต ํจํค์ง, ํด๋์ค ์ด๋ฆ ๋ฑ ๋ชจ๋ ๊ฐ๊ฒ test์๋ ์์ฑํด์ค๋ค
→ @Test ์ด๋ ธํ ์ด์ ์ ์ ์ธํ์ฌ ๋ฉ์๋๊ฐ ๋จ์ ํ ์คํธ ๋ฉ์๋์์ ์ ์ธํ๋ค
ํ์ ๋ ํฌ์งํ ๋ฆฌ ํ ์คํธ ์ผ์ด์ค
โช ํ ์คํธ ์ผ์ด์ค๋ ๊ธฐ๋ณธ์ ์ผ๋ก given → when → then ํจํด์ผ๋ก ์์ฑํ๋๊ฒ์ด ์ข๋ค.
given ↔ ์ฃผ์ด์ง ์ํฉ์์
when ↔ ์ด๊ฒ์ ์คํํ์ ๋
then ↔ ์ด๋ฐ ๊ฒฐ๊ณผ๊ฐ ๋์์ผํ๋ค!
test/repository/MemoryMemberRepositoryTest
( ↔ main/repository/MemoryMemberRepository ์ ๋ํ test code)
save ํ ์คํธ
MemoryMemberRepository repository = new MemoryMemberRepository();
@Test
public void save(){
// given
Member member = new Member();
member.setName("spring");
// when
repository.save(member);
// then
Member result = repository.findById(member.getId()).get();
assertThat(member).isEqualTo(result);
}
โช get()์ผ๋ก Optional๊ฐ์ฒด๋ฅผ ๊บผ๋ด์ given member์ ๊ฐ์์ง ๋น๊ตํ๋ ๋ฉ์๋
โช assertThat(member).isEqualTo(result)
→ ์์ฆ ๋ง์ด ์ฌ์ฉํ๋ ๋ฉ์๋๋ก, ๋ฐฉํฅ์ฑ์ด ํท๊ฐ๋ฆฌ์ง ์๋๋ค๋ ์ฅ์
→ .assertEquals(member, result) ๋ฉ์๋๋ ๊ฐ์ ๊ธฐ๋ฅ
findByName ํ ์คํธ
@Test
public void findByName(){
// given
Member member1 = new Member();
member1.setName("spring1");
repository.save(member1);
Member member2 = new Member();
member2.setName("spring1");
repository.save(member2);
// when
Member result = repository.findByName("spring1").get();
// then
assertThat(result).isEqualTo(member1);
}
given ↔ spring1, spring2๋ผ๋ ํ์์ด ๊ฐ์ ๋ ์ํฉ
when ↔ “spring1” ๊ฐ์ฒด๋ฅผ ๊บผ๋์ ๋ (์๋์ง ์๋์ง ๋ชจ๋ฅด๋๊น Optional ๊ฐ์ฒด)
then ↔ isEqualTo() ๋ก ๋น๊ต
findAll ํ ์คํธ
**@Test
public void findAll(){
// given
Member member1 = new Member();
member1.setName("spring1");
repository.save(member1);
Member member2 = new Member();
member2.setName("spring1");
repository.save(member2);
// when
List<Member> result = repository.findAll();
// then
assertThat(result.size()).isEqualTo(2);
}**
โช ๊ฐ์ฒด 2๊ฐ ๋ชจ๋ ์ ์ ์ฅ๋์๋ ํ์ธํ๋ ๋ฉ์๋
์ด์ ํ ์คํธ ํด๋ณด์
๊ทธ๋ฐ๋ฐ
ํ ์คํธ๊ฐ findAll → findByName ์์๋ก ์คํ๋์๊ธฐ ๋๋ฌธ์ ๋ฐ์ํ ์๋ฌ์ด๋ค.
(findAll() ์คํ๋๋ฉด์ ์ด๋ฏธ spring1, spring2 ๊ฐ์ฒด๊ฐ ์ ์ฅ๋์๊ธฐ ๋๋ฌธ์ findByName์์ ๋ฌธ์ ๋ฐ์)
โช ๋ฉ์๋๋ ์์๋๋ก ๋์๊ฐ์ง ์๋๋ค,, ์์์ ๋์๊ฐ๊ธฐ ๋๋ฌธ์
→ ์์ ์์กด์ ์ผ๋ก ์ค๊ณํ๋ฉด ์ ๋ ์๋๋ค!
โช ์ด๋ฐ ๋ฌธ์ ๋ฅผ ํด๊ฒฐํ๊ธฐ ์ํด ํ ์คํธ๋ฅผ ํ ๋ฒ ๋๋ฆด ๋๋ง๋ค ๋ฐ์ดํฐ๋ฅผ ํด๋ฆฌ์ด ํด์ฃผ์ด์ผ ํ๋ค.
@AfterEach๋ฅผ ํตํ ์ฝ๋ฐฑํจ์
@AfterEach
public void afterEach(){
repository.clearStore();
}
๊ฐ ํ ์คํธ๊ฐ ์ข ๋ฃ๋ ๋๋ง๋ค ์ด์ ์ ํ ์คํธ์ ์ํด ์ ์ฅ๋ ๋ฐ์ดํฐ๋ค์ ์ญ์ ํด์ฃผ์ด์ผ ํ๋ค.
โช test ํด๋์ค๋ถํฐ ๋ง๋ค๊ณ ๋์ repository๋ฅผ ๋ง๋๋ ๋ฐฉ๋ฒ์ ํ ์คํธ ์ฃผ๋ ๊ฐ๋ฐ TDD๋ผ๊ณ ํ๋ค.
โช ํนํ ์ฌ๋ฌ๋ช ์ด์ ๊ฐ๋ฐํ ๋๋ testcode๊ฐ ํ์์ด๊ธฐ ๋๋ฌธ์ ๊น์ด์๊ฒ ๊ณต๋ถํ๋ ๊ฒ์ ์ถ์ฒํ๋ค๊ณ ํ๋ค.
์๋ฃ ์ถ์ฒ
์ธํ๋ฐ - ์คํ๋ง ์ ๋ฌธ ์ฝ๋๋ก ๋ฐฐ์ฐ๋ ์คํ๋ง ๋ถํธ, ์น MVC, DB ์ ๊ทผ ๊ธฐ์ (๊น์ํ)