@AfterEach
@AfterEach를 사용하면 각 테스트가 종료될 때 마다 이 기능을 실행한다.
@BeforeEach
각 테스트 실행 전에 호출됨
테스트가 서로 영향이 없도록 항상 새로운 객체를 생성하고, 의존관계도 새로 맺어줌
Optional<T>
NullPointerException을 방지할 수 있음
null이 올 수 있는 T타입의 객체의 값을 감싸는 Wrapper클래스
복잡한 조건문 없이도 null값으로 인해 발생하는 예외처리를 할 수 있음
of() 메소드나 ofNullable() 메소드를 사용하여 객체를 생성할 수 있음
명시된 값이 null이면 비어있는 Optional객체를 반환함
Streams의 findAny()메소드와 findFirst()메소드의 차이
findFirst() : 병렬 처리시 가장 먼저 찾은 선입된 요소 한개를 Optional에 담아서 리턴
findAny() : 병렬 처리시 가장 먼저 찾은 후입된 요소 한개를 Optional에 담아서 리턴
ifPresent()
Optional 객체의 값이 null인지 여부를 판단해 줌
null이 아니라면(true) 인자로 받은 람다식을 적용해줌
null이라면(false) 람다식이 실행되지 않음
assertThat().isEqualTo 메소드 사용법
assertThat().isEqualTo()의 형태로 기본타입 또는 참조타입의 두 값을 비교할 때 사용 * 두 값이 같지 않을경우 test실패 상태를 반환함
assertEquals()메소드
예상값과 실제값을 비교하는데 사용되는 메소드
assertEquals(예상값, 실제값)
두 값이 다르면 테스트 실패 예외를 발생시킴
비교되는 매개값의 타입은 제한없이 모두 가능
assertThrows()메소드
두 번째 인자인 람다식을 실행하여 첫 번째 인자인 예상되는 예외와 같은지, 혹은 캐스팅이 가능한 상속 관계의 예외인지 검사함
예상되는 예외가 발생하면 테스트에 성공함
IllegalStateException
특정 메소드가 허용되지 않는 상태에서 호출될 때 발생
보통은 객체의 상태가 메소드를 호출하기에 적합하지 않은 경우에 발생
[코드 뜯기]
package hello.hellospring.domain;
import hello.hellospring.reepository.MemberRepository;
public class Member { //자바 빈 규약
//멤버 변수
private Long id; //아이디
private String name; //이름
public Member() {}
//getter, setter
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;
}
}
package hello.hellospring.reepository;
import hello.hellospring.domain.Member;
import java.util.List;
import java.util.Optional;
// DB가 정해지지 않았다는 가정하에 임시 저장소에 관련된 인터페이스
public interface MemberRepository {
Member save(Member member); //아이디, 이름 저장 메소드
Optional<Member> findById(Long id); //아이디 찾기 메소드
Optional<Member> findByName(String name); //이름 찾기 메소드
List<Member> findAll(); //리스트 조회 메소드
}
package hello.hellospring.repository;
import hello.hellospring.domain.Member;
import java.util.*;
// MemberRepository 인터페이스 구현 객체
public class MemoryMemberRepository implements MemberRepository {
/** Member 객체 저장소
* <아이디(key), 멤버객체(value)>순으로 저장
*/
private static Map<Long, Member> store = new HashMap<>();
/** 아이디를 생성해주는 sequence
*/
private static long sequence = 0L;
/** 아이디 저장 메소드
* @param member
* @return Member member
*/
@Override
public Member save(Member member) {
member.setId(++sequence); //시퀀스로 번호 생성
store.put(member.getId(), member); //store 변수에 아이디, 멤버객체 입력
return member;
}
/**아이디 찾기 메소드
* @param id
* @return Member member
*/
@Override
public Optional<Member> findById(Long id) {
return Optional.ofNullable(store.get(id)); //null이 발생될 수 있기 때문에 Optional에 담아서 리턴함
}
/**Memeber 객체들 전체 찾기 메소드
* @return ArrayList<member>
*/
@Override
public List<Member> findAll() {
return new ArrayList<>(store.values()); //store의 값(Member 객체)들을 ArrayList에 담아서 리턴함
}
/**이름 찾기 메소드
* @param name
* @return Member member
*/
@Override
public Optional<Member> findByName(String name) {
return store.values().stream() //Streams를 이용한 Map 컬렉션 제어
.filter(member -> member.getName().equals(name)) //filter()메소드를 이용하여 매개변수의 name과 같은 값을 가진 member객체 filter함
.findAny(); //제일 처음 찾은 객체를 findAny 특성상 Optional에 담아서 반환 (null이 발생될 수 있기 때문에 Optional에 담아서 리턴함)
}
/** store 변수 내부의 키와 값들을 전체 삭제하는 메소드
*/
public void clearStore() {
store.clear();
}
}
package hello.hellospring.service;
import hello.hellospring.domain.Member;
import hello.hellospring.repository.MemberRepository;
import java.util.List;
import java.util.Optional;
public class MemberService {
// 기존에는 회원 서비스가 메모리 회원 리포지토리를 직접 생성하게 함
// private final MemberRepository memberRepository = new MemoryMemberRepository();
// 외부에서 생성된 MemberRepository 객체를 매개값으로 받음으로서
// MemberService 객체 생성됨 (의존성 주입)
private final MemberRepository memberRepository;
public MemberService(MemberRepository memberRepository) {
this.memberRepository = memberRepository;
}
/**
* 회원가입
*/
public Long join(Member member) {
//중복 회원 검증
validateDuplicateMember(member);
//memberRepository 객체의 store저장소에 save() 메소드 사용하여 회원정보 저장
memberRepository.save(member);
//sequence로 생성된 아이디 리턴
return member.getId();
}
/**
* 중복 회원 검증
* @param member
*/
private void validateDuplicateMember(Member member) {
// memberRepository 객체의 findByName()메소드를 이용하여 Optional에 담은 Member객체 반환
memberRepository.findByName(member.getName())
//Optional<T>의 ifPresent()메소드를 이용하여 결과가 true이면 람다식을 적용함
.ifPresent(m -> {
//예외 생성하여 메소드를 호출한 곳으로 throw함
throw new IllegalStateException("이미 존재하는 회원입니다.");
});
}
/**
* 전체 회원 조회
*/
public List<Member> findMembers() {
// memberRepository 객체의 findAll() 메소드로 회원 이름 전체 조회
return memberRepository.findAll();
}
/**
* 회원 한명 조회
* @param memberId
* @return
*/
public Optional<Member> findOne(Long memberId) {
// memberRepository 객체의 findAll() 메소드로 특정 회원 이름 조회
return memberRepository.findById(memberId);
}
}
[테스트 코드 뜯기]
package hello.hellospring.repository;
import hello.hellospring.domain.Member;
import hello.hellospring.reepository.MemoryMemberRepository;
import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.Test;
import java.util.List;
import java.util.Optional;
import static org.assertj.core.api.Assertions.assertThat;
// 테스트 코드
public class MemoryMemberRepositoryTest {
// 저장소 객체 생성
MemoryMemberRepository repository = new MemoryMemberRepository();
@AfterEach // 각테스트들이 종료될 때 마다 메모리DB에 저장된 데이터를 삭제함
public void afterEach() {
repository.clearStore();
}
// 객체 저장 테스트
@Test
public void save() {
//Member객체 생성
Member member = new Member();
//Member객체에 이름 저장
member.setName("spring");
//MemoryMemberRepository 클래스의 save()메소드를 이용하여 Member객체 저장하면서
//아이디는 시퀀스로 저장
repository.save(member);
//MemoryMemberRepository의 findById()메소드에 매개값으로 id를 넣고
//Optional 객체의 get()메소드를 이용하여 id 추출함
//해당 id가 key값인 객체를 store 변수(HashMap)에서 가져옴
Member result = repository.findById(member.getId()).get();
//찾은 객체와 위의 저장된 객체가 일치 하는지 확인
assertThat(result).isEqualTo(member);
}
//이름찾기 테스트
@Test
public void findByName() {
Member member1 = new Member(); //member1 객체 생성
member1.setName("spring1"); //member1 객체에 이름 저장
repository.save(member1); //member1 객체 저장소에 저장
Member member2 = new Member(); //member1 객체 생성
member2.setName("spring2"); //member1 객체에 이름 저장
repository.save(member2); //member1 객체 저장소에 저장
// MemoryMemberRepository의 findByName()메소드에 매개값으로 위의 저장 Member객체들 중
// 한 객체의 이름 넣고, store(HashMap)의 값들중 stream의 fiter()메소드를 이용하여
// findAny()메소드를 이용하여 가장 먼저 찾은 요소 한개를 Optional에 담아서 리턴함
Member result = repository.findByName("spring1").get();
// 찾은 객체와 위의 저장된 객체가 일치 하는지 확인
assertThat(result).isEqualTo(member1);
}
//회원 리스트 조회 테스트
@Test
public void findAll() {
Member member1 = new Member(); //member1 객체 생성
member1.setName("spring1"); //member1 객체에 이름 저장
repository.save(member1); //member1 객체 저장소에 저장
Member member2 = new Member(); //member1 객체 생성
member2.setName("spring2"); //member1 객체에 이름 저장
repository.save(member2); //member1 객체 저장소에 저장
// MemoryMemberRepository의 findAll()메소드를 이용하여
// store의 값들만 ArrayList<member>()에 저장하고 리턴함 (HashMap은 순서가 없기 때문에 무작위로 저장됨)
List<Member> result = repository.findAll();
// 위 두 객체가 저장되어있는지 ArrayList의 size확인
assertThat(result.size()).isEqualTo(2);
}
}
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.BeforeEach;
import org.junit.jupiter.api.Test;
import static org.assertj.core.api.Assertions.assertThat;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertThrows;
// 서비스 테스트
public class MemberServiceTest {
MemberService memberService;
MemoryMemberRepository memberRepository;
//테스트 실행 전 MemberService 클래스의 구조가 의존성 주입이 되었기 때문에 객체를 생성하여 주입함
@BeforeEach
public void beforeEach() {
memberRepository = new MemoryMemberRepository();
memberService = new MemberService(memberRepository);
}
//테스트 실행 후 저장소의 내용을 지워줌
@AfterEach
public void afterEach() {
memberRepository.clearStore();
}
//회원가입 메소드
public void 회원가입() throws Exception { //발생하는 Exception을 throws함
Member member = new Member(); //member 객체 생성
member.setName("hello"); //member 객체의 멤버변수 이름을 hello라고 저장
//member객체 중복회원검증 후 저장소에 저장, 아이디 리턴함
Long saveId = memberService.join(member);
//리턴한 아이디로 저장소에서 해당객체를 찾음
Member findMember = memberRepository.findById(saveId).get();
//저장소에서 찾은 객체와 새로 저장한 객체의 이름이 일치하는지 확인
assertEquals(member.getName(), findMember.getName());
}
@Test
public void 중복_회원_예외() throws Exception {
//member1 객체 생성 후 이름 저장
Member member1 = new Member();
member1.setName("spring");
//member2 객체 생성 후 이름 저장(Exception발생을 위해 member1과 똑같게 저장함)
Member member2 = new Member();
member2.setName("spring");
//member1만 저장소에 저장함
memberService.join(member1);
//예상되는 예외(IllegalStateException)와 두번째 매개인 람다식을 실행했을 때의 예외가
//같은지 검사함
//예외가 같다면 테스트 계속 진행됨
IllegalStateException e = assertThrows(IllegalStateException.class,
() -> memberService.join(member2));
//예외의 메세지가 같은지 확인함
assertThat(e.getMessage()).isEqualTo("이미 존재하는 회원입니다.");
}
}
'Back-End > Spring Boot' 카테고리의 다른 글
예습) 스프링 입문 (0) | 2023.05.03 |
---|---|
예습) 스프링 기초 (0) | 2023.04.25 |
예습) 스프링 입문을 위한 자바 객체 지향의 원리와 이해 (0) | 2023.04.23 |
댓글