| 일 | 월 | 화 | 수 | 목 | 금 | 토 |
|---|---|---|---|---|---|---|
| 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 | 29 | 30 |
- @Transactional
- Dead Letter Queue
- @ComponentScan
- 페이징
- AWS
- Web
- securitycontextholderfilter
- mybatis
- 서블릿 컨테이너
- 지연 로딩
- DI
- JPA
- Spring
- kafka
- DLQ
- JWT
- redis
- dockerhub
- 쿠버네티스
- CORS
- JdbcTemplate
- Spring Container
- docker compose
- MSA
- Spring Data JPA
- Routing Key
- JPQL
- 스프링 부트
- 컨테이너
- docker
- Today
- Total
look-forest
Mockito 본문
Mockito 소개
자바 테스트에서 사용하는 Mock 프레임워크.
spring-boot-starter-test에서 자동으로 Mockito 추가해 줌
- Mock: 진짜 객체와 비슷하게 동작하지만 프로그래머가 직접 그 객체의 행동을 관리하는 객체.
- Mockito: Mock 객체를 쉽게 만들고 관리하고 검증할 수 있는 방법을 제공
단위 테스트에 대하여
단위 테스트를 논할 때, '단위'의 기준은 정하기 나름이다. 클래스가 될 수도 있고, 기능이 될 수도 있다.
이미 존재하는 객체를 굳이 Mock으로 만들 필요는 없다고 생각한다.
다만, 내가 통제하기 힘든 외부 API 의 테스트 환경이 없다면 Mocking을 하는 수 밖에 없다.
Mock을 활용한 테스트
- Mock을 만드는 방법
- Mock이 어떻게 동작해야 하는지 관리하는 방법 (Stubbing)
- Mock의 행동을 검증하는 방법 (Verifying)
1. Mock 객체 만들기
- Mockito.mock() 메소드로 만드는 방법
- @Mock 애노테이션으로 만드는 방법
- JUnit 5 extension으로 MockitoExtension을 사용해야 한다.
- 필드 / 메소드 매개변수
※ 진짜 객체
- @InjectMocks : 테스트하려는 실제 객체(테스트 대상)에 @Mock 또는 @Spy로 선언된 객체들을 자동으로 주입.
- @Spy : 실제 클래스의 인스턴스를 생성하여 사용
- @MockitoBean : Spring Boot 테스트에서 Spring ApplicationContext에 등록된 실제 빈(bean)을 Mockito의 목(mock) 객체로 대체할 때 사용 (@Mock은 ApplicationContext에 자동으로 등록되지 않음)
※ MockitoExtension을 쓸 때는 Bean을 안붙여도 되는데, @SpringbootTest는 Bean을 붙이고 @Autowired를 쓴다.
@ExtendWith(MockitoExtension.class) //가짜 환경이라 Spring 관련 Bean들이 없는 환경
class UserServiceTest {
//테스트 대상 클래스의 인스턴스를 생성하고, 해당 클래스의 필드에 적절한 목(Mock) 객체를 자동으로 주입
@InjectMocks //모든 Mock들이 주입된다
private UserService userService;
@Mock //가짜 객체를 생성해 넣는다
private UserRepository userRepository;
@Spy //Spring IOC 에 있는 진짜 Bean 을 넣는다
private PasswordEncoder passwordEncoder;
}
2. Mock 객체 Stubbing
메소드 스텁(method stub) : 다른 프로그래밍 기능을 대리하는 코드를 의미
모든 Mock 객체의 행동(default, stubbing 전)
- Null을 리턴한다. (Optional 타입은 Optional.empty 리턴)
- Primitive 타입은 기본 Primitive 값.
- 콜렉션은 비어있는 콜렉션.
- Void 메소드는 예외를 던지지 않고 아무런 일도 발생하지 않는다
Mock 객체를 조작하면
- 특정한 매개변수를 받은 경우 특정한 값을 리턴하거나 예외를 던지도록 만들 수 있다.
- 메소드가 동일한 매개변수로 여러번 호출될 때 각기 다르게 행동하도록 조작할 수도 있다.
Mockito.when(), Mockito.doThrow() 메소드를 통해 stubbing이 가능하다.
@Test
void stubbing(@Mock MemberService memberService) {
Member member = new Member();
member.setId(1L);
member.setEmail("test@Test.com");
//stubbing
Mockito.when(memberService.findById(1L)).thenReturn(Optional.of(member));
Mockito.doThrow(new IllegalArgumentException()).when(memberService).validate(1L);
assertThat(member).isEqualTo(memberService.findById(1L).get());
assertThrows(IllegalArgumentException.class, () -> memberService.validate(1L));
//stubbing : 여러번 호출될 때 각기 다르게 행동하도록 지정
Mockito.when(memberService.findById(any()))
.thenReturn(Optional.of(member))
.thenThrow(new IllegalArgumentException())
.thenReturn(Optional.empty());
assertEquals(member, memberService.findById(7L).get());
assertThrows(IllegalArgumentException.class, () -> memberService.findById(1L));
assertEquals(Optional.empty(), memberService.findById(1L));
}
3. Mock 객체의 행동을 검증하는 방법 (Verifying)
Mock 객체가 어떻게 사용이 됐는지 확인할 수 있다.
verify 메소드를 사용하면,
특정 메소드가 특정 매개 변수로 몇 번 호출 되었는지, 최소 한 번은 호출 됐는지, 전혀 호출되지 않았는지 등
@Test
void createNewStudy(@Mock MemberService memberService) {
...
Mockito.verify(memberService, times(1)).notify(study);
// verifyNoMoreInteractions(memberService);
Mockito.verify(memberService, times(1)).notify(member);
Mockito.verify(memberService, never()).validate(anyLong());
//notify(study) 호출 후 notify(member) 호출 여부 확인
InOrder inOrder = Mockito.inOrder(memberService);
inOrder.verify(memberService).notify(study);
inOrder.verify(memberService).notify(member);
}
BDD 스타일 Mockito API
BDD: Behavior Driven Development.
애플리케이션이 어떻게 “행동”해야 하는지에 대한 공통된 이해를 구성하는 방법으로, TDD에서 창안.
Mockito는 BddMockito라는 클래스를 통해 BDD 스타일의 API를 제공한다.
기존 api의 when, verify 등을 given / when / then 구조에 맞춰 명명하는 정도이다.
import static org.mockito.BDDMockito.given;
import static org.mockito.BDDMockito.then;
//Mockito BDD 스타일 API (Behavior Driven Development)
@Test
void BDD_Style(){
// Given
StudyService studyService = new StudyService(memberService, studyRepository);
assertNotNull(studyService);
Member member = new Member();
member.setId(1L);
member.setEmail("test@Test.com");
Study study = new Study(10, "테스트");
given(memberService.findById(1L)).willReturn(Optional.of(member));
given(studyRepository.save(study)).willReturn(study);
// When
studyService.createNewStudy(1L, study);
// Then
then(memberService).should(times(1)).notify(study);
then(memberService).should(times(1)).notify(member);
then(memberService).shouldHaveNoMoreInteractions();
}
참고 자료 & 이미지 출처
더 자바, 애플리케이션을 테스트하는 다양한 방법 (백기선 님)
Mockito 레퍼런스
'Test > 애플리케이션을 테스트하는 다양한 방법' 카테고리의 다른 글
| Web MVC / Security / JPA 관련 test (0) | 2024.12.15 |
|---|---|
| Junit 5 (2) | 2024.11.10 |
| 테스트 - DB 연동 (0) | 2024.08.17 |
| 테스트의 종류 (0) | 2021.05.01 |