1. 비즈니스 요구사항 정리
🍃 일반적인 웹 어플리케이션의 계층구조
🔸Controller : MVC동작, API 통신에서 컨트롤러의 역할( ex. 요청처리, 응답생성, 경로매핑 )
🔸Service : 도메인을 가지고 핵심 비즈니스 로직의 구현( ex. 중복가입제어, 로그인 아이디 비밀번호 일치판단.. )
🔸Domain : 데이터베이스에 저장하고 관리되는 비즈니스 도메인 객체
🔸Repository : 데이터베이스에 접근, 도메인 객체를 저장하고 관리
데이터베이스가 선정되지 않았기에 Repository는 여러 상황에따라 변경될수 있도록 인터페이스로 설계한다.( 추후 단순 JDBC, Mybatis, JPA 등으로 구현가능 )
초기개발단계에서는 가장 가볍고 간단한 메모리기반 저장소 구현체를 사용한다.
2. 회원 도메인과 리포지토리
🔸 회원객체( Member ) : 멤버변수를 가지고 이에 대한 getter, setter를 가진다. [ src/main/java/hello/hello_spring/domian ]
🔸 회원리포지토리 인터페이스( MemberRepository ) : 회원도메인에 접근, 관리할 수 있도록 기본적인 메서드(save, findById, findByName, findAll)을 가진다. [ src/main/java/hello/hello_spring/repository ]
🔸 회원리포지토리 메모리구현체 ( MemoryMemberRepository ) : HashMap객체를 이용하여 저장소를 만들고 각 리포지토리 기능을 구현 [ src/main/java/hello/hello_spring/repository ]
Optional(java.util.Optional)
: null을 직접 사용하는 대신 값을 감싸는 컨테이너 객체로, 값이 존재할 수도 있고 존재하지 않을 수도 있는 상황을 명확하게 처리할 수 있도록 도와준다. ( java8에서 도입 )
Optional.of(T value) : 값이 반드시 존재해야하는 경우 사용, null이면 NullPointerException 발생
Optional.ofNullable(T value) : 값이 존재할수도 있고 존재하지 않을 수도 있는 경우 사용, null이면 빈 Optional 생성
isPresent() : 값의 존재여부를 반환(True/False), 동작을 입력하면 값이 존재할 경우 동작하게 됨
get() : 값이 존하면 반환, 존재하지 않으면 NoSuchElementException 발생
orElse(T other) : 값이 존재하면 반환, 존재하지 않으면 입력한 대체값을 반환
orElseGet(Supplier<? extends T> other) : 값이 존재하면 반환, 존재하지 않으면 제공된 함수 실행하여 값 반환
3. 회원 리포지토리 테스트케이스 작성
코드를 코드로 검증하는 방식
🍃 JUnit framwork
메인메서드, 컨트롤러를 거치지 않고 기능을 실행해볼 수 있다. 준비하고 실행하는 것이 간단하고 반복적이고 다량의 테스트를 수행할 수 있는 장점이 있다.
※ 관례적인 방식 : src/main/java 하의 동일한 패키지를 src/test/java 하에 구축하고 테스트 클래스( 클래스명+Test )를 만들어 기능별로 테스트 케이스( 메서드 )를 작성한다.
테스트 메서드(테스트 케이스) 단위로 어노테이션(@Test : org.junit.jupiter.api.Test)을 붙여서 실행한다. 혹은 클래스 단위에서 전체에서 실행해볼 수도 있다.
🔸 org.junit.jupiter.api.Assertions
: JUnit 5에서 제공하는 클래스 중 하나로, 정적메서드를 통해 테스트 코드에서 조건을 검증할 수 있다.
- assertEquals(expected, actual) : 두 값이 같은지 확인한다.
- assertNotEquals(unexpected, actual) : 두 값이 같지 않은지 확인한다.
- assertTrue(condition): 조건이 참인지 확인한다.
- assertThrows(exceptionClass, executable): 해 예외가 발생하는지 확인한다.
🔸 org.assertj.core.api.Assertions
: AssertJ에서 제공하는 클래스로 단언문(assertion)을 보다 간결하고 읽기 쉽게 작성할 수 있도록 도와준다.
AssertJ : Java용 테스트 라이브러리로, 유창한(fluent) API를 제공하여 테스트 코드의 가독성을 높여준다. 기존의 JUnit이나 TestNG와 함께 사용된다.
AssertJ의 단언문은 assertThat()으로 시작하며, 그 뒤에 다양한 조건( isEqualTo, isNotEqualTo, isNotNull, contains, hasSize 등)을 붙여서 사용할 수 있다.
🔸 AfterEach
: 각 테스트케이스 메서드가 끝날때마다 실행되는 콜백 메서드, 어노테이션(@AfterEach : org.junit.jupiter.api.AfterEach)를 붙여서 실행한다.
각 테스트케이스들은 클래스 멤버변수로 저장소를 공유하게 되기에 클래스 단위에서 여러 테스트 케이스를 실행하는 경우 이전의 테스트 결과가 남게 된다.( 변수명 중복가능 문제 ) 또한 테스트케이스 실행순서도 보장되지 않는다. ( 테스트간 의존관계없이 독립성이 유지되어야한다. )
각 테스트 케이스가 끝날때마다 실행되는 작업에 저장소를 비워주는 처리를 진행해야한다.
저장소를 비롯한 공용데이터를 초기화하는 작업이 콜백메서드에서 수행되어야한다.
4. 회원 서비스 개발
서비스를 구현하기 위해서는 리포지토리가 필요하다.
테스트코드는 빌드시 포함되지 않는다. 직관적인 이해를 위해 한글이름을 사용해도 좋다.
🔸테스트 문법 [ given, when, then문법 ]
- given : 주어진 상황(조건), 기반 데이터
- when : 기능 실행
- then : 결과 확인
🔸BeforeEach를 통한 DI 방식구현
: 각 테스트케이스 메서드가 수행되기 이전에 실행되는 콜백 메서드, 어노테이션(@BeforeEach : org.junit.jupiter.api.BeforeEach)를 붙여서 실행한다.
public class MemberService {
private final MemberRepository memberRepository = new MemoryMemberRepository();
...
}
class MemberServiceTest {
MemberService memberService = new MemberService();
MemoryMemberRepository memberRepository = new MemoryMemberRepository();
...
}
서비스가 리포지토리를 직접 생성하는 기존방식
실제 서비스에서 사용하는 리포지토리와 서비스 테스트에서 사용하는 리포지토리가 서로 다른 객체로 개별 생성된다.
여러 위험성이 발생할 수 있다.
ex) 저장소를 메모리에서 static으로 구현할때는 동일한 것으로 공유하지만 그렇지 않은 경우 다른 DB를 이용하는 위험성
public class MemberService {
private final MemberRepository memberRepository;
public MemberService(MemberRepository memberRepository) {
this.memberRepository = memberRepository;
}
...
}
class MemberServiceTest {
MemberService memberService;
MemoryMemberRepository memberRepository;
@BeforeEach
public void beforeEach() {
memberRepository = new MemoryMemberRepository();
memberService = new MemberService(memberRepository);
}
}
서비스가 리포지토리를 직접 생성하는 것이 아니라, 외부에서 생성된 것을 넣어주도록 하는 방식( 의존성 주입 )
테스트케이스별로 독립적이고 개별적인 서비스와 리포지토리가 생성되어 테스트의 독립성이 보장된다.
'web programming' 카테고리의 다른 글
[ 스프링 입문 ] 웹 MVC (0) | 2024.09.02 |
---|---|
[ 스프링 입문 ] 스프링 빈과 의존관계 (0) | 2024.09.02 |
[ 스프링 입문 ] 프로젝트 환경설정, 스프링 웹개발 기초 (1) | 2024.08.24 |
JPA(Java Persistence API) 기본개념 (0) | 2024.03.10 |
SpringBoot 기본개념 (0) | 2024.03.10 |