Repository 만들기
Repository는 기본적으로 Entity를 DB에 저장하고 불러오는 작업을 한다.
현재 어떤 DB를 사용할지 결정이 되지 않았고, 테스트용 Repository를 선언해 개발을 진행하다가,
DB가 결정되면 해당 Repository로 갈아 끼기로 한 시나리오라고 가정하자.
우선 나중에 Repository를 구현체만 바꿔서 갈아 끼울 수 있도록 동일한 인터페이스를 갖도록 하기 위해
Repository에 들어갈 함수들을 모아놓은 인터페이스를 정의해야 한다.
Repository들을 모아놓을 repository 패키지를 생성하고, 그 안에 아래의 코드를 작성한다.
MemberRepository.java
package com.devjaewoo.hellospring.repository;
import com.devjaewoo.hellospring.domain.Member;
import java.util.List;
import java.util.Optional;
public interface MemberRepository {
Member save(Member member);
Optional<Member> findById(Long id);
Optional<Member> findByName(String name);
List<Member> findAll();
}
repository 패키지에 위의 인터페이스를 구현한 테스트용 Repository도 작성해준다.
MemoryMemberRepository.java
package com.devjaewoo.hellospring.repository;
import com.devjaewoo.hellospring.domain.Member;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.concurrent.ConcurrentHashMap;
public class MemoryMemberRepository implements MemberRepository {
private static final Map<Long, Member> store = new ConcurrentHashMap<>();
private static long sequence = 0L;
@Override
public Member save(Member member) {
member.setId(++sequence);
store.put(sequence, member);
return member;
}
@Override
public Optional<Member> findById(Long id) {
return Optional.ofNullable(store.get(id));
}
@Override
public Optional<Member> findByName(String name) {
return store.values().stream()
.filter(member -> member.getName().equals(name))
.findAny();
}
@Override
public List<Member> findAll() {
return new ArrayList<>(store.values());
}
public void clearStore() {
store.clear();
}
}
Repository 테스트 케이스 작성
조금 전에 만든 Repository가 정상 작동하는지 테스트해봐야 한다.
하지만 기능 테스트를 위해 main에 테스트 코드를 작성하고 Spring 서버를 다시 켜서 테스트하려면 시간이 너무 오래 걸리고, main에 불필요한 코드가 추가된다.
이때 JUnit이라는 라이브러리를 통해 테스트를 간편하게 진행할 수 있다.
보통 테스트 코드는 src/test 폴더에 있다.
main의 폴더구조와 동일하게 test 안에 repository 패키지를 만들고, 그 안에 MemoryMemberRepositoryTest 테스트 클래스를 생성한다.
MemoryMemberRepositoryTest.java
package com.devjaewoo.hellospring.repository;
import com.devjaewoo.hellospring.domain.Member;
import org.assertj.core.api.Assertions;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import java.util.List;
import static org.assertj.core.api.Assertions.*;
public class MemoryMemberRepositoryTest {
MemoryMemberRepository memberRepository = new MemoryMemberRepository();
@BeforeEach
public void setUp() {
memberRepository.clearStore();
}
@Test
public void save() {
Member member = new Member();
member.setName("spring");
memberRepository.save(member);
Member result = memberRepository.findById(member.getId()).orElse(null);
assertThat(result).isEqualTo(member);
}
@Test
public void findByName() {
Member member1 = new Member();
member1.setName("spring1");
memberRepository.save(member1);
Member member2 = new Member();
member2.setName("spring2");
memberRepository.save(member2);
Member result = memberRepository.findByName("spring2").orElse(null);
assertThat(result).isEqualTo(member2);
}
@Test
public void findAll() {
Member member1 = new Member();
member1.setName("spring1");
memberRepository.save(member1);
Member member2 = new Member();
member2.setName("spring2");
memberRepository.save(member2);
List<Member> result = memberRepository.findAll();
assertThat(result.size()).isEqualTo(2);
}
}
이렇게 모든 테스트가 통과하면 성공이다.
테스트 코드 중간에 @BeforeEach라는 어노테이션이 붙은 함수가 있다.
만약 이 함수가 없다면 한 테스트에서 save 한 값이 다른 테스트에 영향을 주기 때문에 정상적인 결과가 나오지 않는다.
지금이야 프로그램의 코드가 몇십 줄밖에 되지 않아 결함이 있으면 눈으로 확인할 수 있지만, 코드가 몇만 ~ 몇십만 줄을 넘어가면 눈으로 일일이 확인할 수 없기에 테스트 코드가 필수적이라고 한다.
출처
'Study > Spring Boot' 카테고리의 다른 글
[Spring Boot] 의존성 주입과 스프링 빈 등록 (0) | 2022.02.13 |
---|---|
[Spring Boot] Service와 테스트 케이스 만들기 (0) | 2022.02.13 |
[Spring Boot] JSON 형태로 객체 반환하기 (0) | 2022.02.12 |
[Spring Boot] Spring Boot 동작 구조 (0) | 2022.02.12 |
[Spring Boot + Kotlin] 프로젝트 생성 (0) | 2021.09.15 |