- 비즈니스 요구사항 정리
- 웹 애플리케이션 계층 구조 설계
- 테스트 케이스
이번 회원관리 예제는 일반적인 웹 애플리케이션 계층 구조 맞추어 설계하며 학습하였다.
테스트 케이스의 경우, JUnit
테스트 프레임을 사용한다.
일반적인 웹 애플리케이션 계층 구조로, 컨트롤러, 서비스, 리포지토리, 도메인 객체, 데이터베이스와 같이 구성된다.
컨트롤러 : 웹 MVC의 컨트롤러 역할
서비스 : 비즈니스 도메인 객체가 핵심 비즈니스 로직이 동작하도록 구현
리포지토리 : 데이트베이스에 접근하며, 도메인 객체를 DB에 저장하고 관리
도메인 : 주로 데이터베이스에 저장하고 관리되는 비즈니스 도메인 객체
아직 데이터베이스가 선정되지 않았기에 메모리 기반의 저장소로 설계하며 학습을 진행했다.
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는 고객이 정하는 ID가 아닌 데이터를 구분하기 위한 ID이다.
private static Map<Long, Member> store = new HashMap<>();
private static long sequence = 0L;
동시성 문제로 HashMap
이 아닌 ConcurrentHashMap
권장하며, sequence의 데이터 타입을 long
이 아닌 Atomic long
권장한다.
공유되는 변수일 경우, 동시성 문제를 고려해야 한다.
private void validateDuplicateMember(Member member) {
memberRepository.findByName(member.getName())
.ifPresent(m -> {
throw new IllegalStateException("이미 존재하는 회원입니다.");
});
}
위 코드는 중복 회원을 검증하는 로직을 구현한 코드로, .ifPresent()
메서드를 통해 검증한다.
.ifPresent()
메서드 경우, 값 존재할 경우, 예외를 발생
@Override
public Optional<Member> findById(Long id) {
return Optional.ofNullable(store.get(id));
}
Optional<T>
의 경우, NullPointerException
을 피하기 위해 null
대신의 초기값으로 사용
Generic Class인
Optional<T>
는 모든 참조변수를 담을 수 있는 Wrapper 클래스
JUnit
프레임워크를 통해 오래 걸리고, 여러 테스트를 한 번에 실행시키기 어렵다는 점들을 해결 !
@Test
public void 중복_회원_예외() throws Exception {
//Given
Member member1 = new Member();
member1.setName("spring");
Member member2 = new Member();
member2.setName("spring");
//When
memberService.join(member1);
//Then
IllegalStateException e = assertThrows(IllegalStateException.class,
() -> memberService.join(member2));//예외가 발생해야 한다.
assertThat(e.getMessage()).isEqualTo("이미 존재하는 회원입니다.");
}
초기 테스트 코드 작성 시에 Given ~ When ~ Then
같은 순서로 테스트를 진행하는 것이 권장한다.
테스트를 할 때에는 독립적으로 실행되야 하며, 순서에 의존관계가 있는 것은 좋은 테스트 ❌
AssertJ
는JUnit
프레임워크에서 제공해주는 라이브러리
@BeforeEach
public void beforeEach() {
memberRepository = new MemoryMemberRepository();
memberService = new MemberService(memberRepository);
}
@AfterEach
public void afterEach() {
repository.clearStore();
}
@BeforeEach
애노테이션이 붙은 메소드의 경우, 테스트 메서드 실행 이전에 수행된다.
@AfterEach
애노테이션이 붙은 메소드의 경우, 테스트 메서드 실행 이후에 수행된다.
📌 본 포스트는 스프링 입문 - 코드로 배우는 스프링 부트, 웹 MVC, DB 접근 기술 통해 학습한 내용을 요약 및 정리한 것입니다.