티스토리 뷰
1. Mock 객체 만들기
내, 외부 API를 사용할 때 인터페이스를 통해 객체를 생성하려면 선언되어 있는 추상 메소드를 모두 구현한
클래스 혹은 익명 클래스를 만들어야 한다.
해당 작업을 Mockito가 해주고 만들어진 Mock 객체를 사용할 수 있다.
위와 같은 구조에서 MemberService, StudyRepository 가 인터페이스이다.
1) MemberService는 규약만 정의해 놓은 상태라고 가정하고,
StudyRepository 는 JpaRepository를 상속받는 인터페이스이다.
public interface MemberService {
Optional<Member> findById(Long memberId);
void validate(Long memberId);
void notify(Study newstudy);
void notify(Member member);
}
public interface StudyRepository extends JpaRepository<Study, Long> {
}
2) StudyService 는 생성자에서 위 두 개의 인터페이스의 참조변수를 파라미터로 갖는다.
public class StudyService {
private final MemberService memberService;
private final StudyRepository repository;
public StudyService(MemberService memberService, StudyRepository repository) {
assert memberService != null;
assert repository != null;
this.memberService = memberService;
this.repository = repository;
}
public Study createNewStudy(Long memberId, Study study) {
Optional<Member> member = memberService.findById(memberId);
// if (member.isPresent()) {
// study.setOwnerId(memberId);
// } else {
// throw new IllegalArgumentException("Member doesn't exist for id: '" + memberId + "'");
// }
study.setOwnerId(member.orElseThrow(() -> new IllegalArgumentException("Member doesn't exist for id: '" + memberId + "'")).getId());
Study newstudy = repository.save(study);
memberService.notify(newstudy);
return newstudy;
}
public Study openStudy(Study study) {
study.open();
Study openedStudy = repository.save(study);
memberService.notify(openedStudy);
return openedStudy;
}
}
3) StudyService 인스턴스를 생성하기 위해 MemberService, StudyRepository 의 Mock 객체를 만든다.
(1) createStudyService
- mock 메소드에 클래스 정보를 넘겨주면서 Mock 객체를 생성할 수 있다.
(2) createStudyService2
- @Mock 어노테이션을 통해 파라미터로 Mock 객체를 받을 수 있다.
- @ExtendWith(MockitoExtension.class) 필요
(3) createStudyService3
- 클래스의 멤버로 선언된 참조변수에 @Mock 어노테이션을 통해 Mock 객체를 만들어 할당할 수 있다.
- @ExtendWith(MockitoExtension.class) 필요
(4) @ExtendWith(MockitoExtension.class)
- JUnit 애서 extention 을 등록할 때 사용하는 @ExtendWith 어노테이션을 통해
- @Mock 어노테이션을 통해 Mock 객체를 만들어 주입해주는 MockitoExtension을 등록한다.
@ExtendWith(MockitoExtension.class)
class StudyServiceTest {
@Mock
MemberService memberService;
@Mock
StudyRepository studyRepository;
@Test
void createStudyService() {
MemberService memberService = mock(MemberService.class);
StudyRepository studyRepository = mock(StudyRepository.class);
StudyService studyService = new StudyService(memberService, studyRepository);
assertNotNull(studyService);
}
@Test
void createStudyService2(@Mock MemberService memberService,
@Mock StudyRepository studyRepository) {
StudyService studyService = new StudyService(memberService, studyRepository);
assertNotNull(studyService);
}
@Test
void createStudyService3() {
StudyService studyService = new StudyService(memberService, studyRepository);
assertNotNull(studyService);
}
}
2. Mock 객체 Stubbing
1) 모든 Mock 객체의 행동
- Null을 리턴한다. (Optional 타입은 Optional.empty 리턴)
- Primitive 타입은 기본 Primitive 값.
- 콜렉션은 비어있는 콜렉션.
- Void 메소드는 예외를 던지지 않고 아무런 일도 발생하지 않는다.
2) Mock 객체를 Stubbing
(1) 특정한 매개변수를 받은 경우 특정한 값을 리턴하도록 설정
- when(), thenReturn() 메소드를 활용
- memberService.findById(1L) 이 호출되면 Optional.of(member) 를 리턴하도록 설정
- memberService.findById(2L) 과 같이 매개변수가 다른 경우 기본적인 Mock 객체의 동작을 따른다.
- Argument matchers 를 참고해 매개변수를 여러 형식으로 설정할 수 있다.
any(), anyInt(), ...
( 예, when(memberService.findById(any())).thenReturn(Optional.of(member)); )
- 테스트 마지막 라인 studyService.createNewStudy() 메소드에서
memberService.findById(1L) 을 호출할 때 Optional.of(member) 를 리턴
@ExtendWith(MockitoExtension.class)
class StudyServiceTest {
@Mock
MemberService memberService;
@Mock
StudyRepository studyRepository;
@Test
void createStudy() {
StudyService studyService = new StudyService(memberService, studyRepository);
System.out.println(memberService.findById(1L)); // Optional.empty
Member member = new Member();
member.setId(1L);
member.setEmail("mandy@gmail.com");
when(memberService.findById(1L)).thenReturn(Optional.of(member));
System.out.println(memberService.findById(1L)); // not empty
System.out.println(memberService.findById(2L)); // Optional.empty
Study study = new Study(10, "java");
Study newStudy = studyService.createNewStudy(1L, study);// createNewStudy 에서 memberService.findById(1L) 호출
}
}
(2) 특정한 매개변수를 받은 경우 특정한 예외를 던지도록 설정
- when(), thenThrow() 활용
@ExtendWith(MockitoExtension.class)
class StudyServiceTest {
@Mock
MemberService memberService;
@Mock
StudyRepository studyRepository;
@Test
void createStudy() {
when(memberService.findById(1L)).thenThrow(new RuntimeException());
}
}
>> 실행 결과
(3) void 메소드가 특정 매개변수를 받거나 호출된 경우 예외를 발생시키도록 설정
- doThrow(), when() 메소드 활용
@ExtendWith(MockitoExtension.class)
class StudyServiceTest {
@Mock
MemberService memberService;
@Mock
StudyRepository studyRepository;
@Test
void createStudy() {
// doThrow(new IllegalArgumentException()).when(memberService).validate(1L);
doThrow(new IllegalArgumentException()).when(memberService).validate(anyLong());
assertThrows(IllegalArgumentException.class, () -> {
memberService.validate(1L);
});
}
}
(4) 메소드가 동일한 매개변수로 여러번 호출될 때 각기 다르게 행동하도록 설정
@ExtendWith(MockitoExtension.class)
class StudyServiceTest {
@Mock
MemberService memberService;
@Mock
StudyRepository studyRepository;
@Test
void createStudy() {
Member member = new Member();
member.setId(1L);
member.setEmail("mandy@gmail.com");
when(memberService.findById(any()))
.thenReturn(Optional.of(member))
.thenThrow(new IllegalArgumentException())
.thenReturn(Optional.empty());
assertEquals("mandy@gmail.com", memberService.findById(1L).get().getEmail());
assertThrows(IllegalArgumentException.class, () -> {
memberService.findById(1L);
});
assertEquals(Optional.empty(), memberService.findById(1L));
}
}
출처
https://www.inflearn.com/course/the-java-application-test 더 자바, 애플리케이션을 테스트하는 다양한 방법(백기선)
'Test > Mockito' 카테고리의 다른 글
[Mockito] 4. BDD Mockito 스타일 API (0) | 2021.12.10 |
---|---|
[Mockito] 3. Mock 객체 확인 (0) | 2021.12.10 |
[Mockito] 1. Mockito 시작하기 (0) | 2021.12.09 |
- Total
- Today
- Yesterday
- Spring Data JPA
- HTTP 헤더
- Ubiquitous Language
- 트랜잭셔널 아웃박스 패턴
- 폴링 발행기 패턴
- clean code
- 이벤트 스토밍
- 스프링 카프카 컨슈머
- 학습 테스트
- Git
- TDD
- named query
- 스프링 예외 추상화
- Stream
- ATDD
- Spring Boot
- 도메인 모델링
- mockito
- spring rest docs
- MySQL
- 클린코드
- JPA
- 마이크로서비스 패턴
- Spring
- 계층형 아키텍처
- 육각형 아키텍처
- H2
- http
- java8
- kafka
일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | ||||||
2 | 3 | 4 | 5 | 6 | 7 | 8 |
9 | 10 | 11 | 12 | 13 | 14 | 15 |
16 | 17 | 18 | 19 | 20 | 21 | 22 |
23 | 24 | 25 | 26 | 27 | 28 |