✏️ Mock
- 테스트 할 때 필요한 실제 객체를 흉내내는 가짜 객체를 만들어 테스트의 효율을 높히기 위해 사용한다.
- 서비스 로직의 부하가 많이걸려, 시간도 너무 오래걸리는 경우
- 서버간 통신이 제대로 되고있는지 확인해야하는 경우
- 요청을 보낼 API 가 작업중인 경우 등등 ...
✏️ Mock 객체의 종류
📍 Stubbing
- Mock 객체를 통해 반환될 미리 준비된 답변을 뜻한다.
when
method 를 사용해 Stubbing 을 사용한다.
when
에 stubing 할 method 를 넣고 method chaining 형식으로 사용된다.
📍 @Mock
- 가짜 객체를 뜻한다.
- 객체의 method 를 호출하려면 반드시 stubbing 을 해야한다.
- 만약 Stubbing 을 생략할경우 Null 또는 0 을 반환한다.
📍 @Spy
- Spy 로 만든 객체는 진짜 객체를 뜻한다.
- Stubbing 을 하지 않는다면 원래 객체의 반환값을,
한다면 Stubbing 한 값을 반환한다.
📍 @InjectMock
- DI 를 Mock 이나 Spy 로 생성된 Mock 객체를 자동으로 주입해주는 어노테이션이다.
📍 MockBean
✏️ Mockito 적용
📍 Dependency
testImplementation 'org.mockito:mockito-core:3.11.2'
📍 Test case
- Mockito 를 사용하기 위해선 Test 객체에 어노테이션을 선언해줘야 한다.
@SpringBootTest
@Transactional
@ExtendWith(MockitoExtension.class)
@RunWith(MockitoJUnitRunner.class)
class StudyServiceTest {
- 응답을 제어해야 하는 method 를 포함한 객체를 Mock Bean 으로 생성해준다.
@MockBean private MemberClient memberClient;
- Mock Bean 으로 생성한 객체의 method 를 Stubbing 해준다.
- 모든 test 를 대상으로 Mock 객체가 필요할 경우 BeforeEach 를 사용하면 중복을 제거할 수 있다.
@BeforeEach
public void beforeEach() {
when(memberClient.updateMyStudy(any()))
.thenReturn(new RsData<>("S-1", "성공", null));
}
- 이제 평소처럼 Test 를 작성하면된다.
- Stubbing 한 객체를 직접적으로 호출하지 않고 다른 method 를 통해 간접적으로 호출하게 되어도 subbing 한 결과가 반환되게 된다.
@Test
@DisplayName("mockito test")
void no0() {
MyStudy myStudy = studyService.create(CreateReqDto.createStudy(1L, "name", "about", "leader", 10));
Study study = studyService.findById(myStudy.getStudy().getId());
assertThat(study.getName()).isEqualTo("name");
}
📍 any() 사용법
- api 의 파라미터에 모든 객체를 뜻하는 any() 는 기본형 데이터타입을 해석할 수 없다.
- int 는
anyInt()
로, String 은 anyString()
으로 수정해야한다.
- any 말고 특정 값을 지정해야 할 땐
eq()
를 사용하면 된다.
when(studyClient.findInput(eq("study"), anyInt(), anyString()))
.thenReturn(new RsData<>("S-1", "성공", list));
- 특정 값을 제외하고 반환값을 만드려면
argTat(s -> !s.equals())
를 사용하면 된다.
when(studyClient.findInput(argThat(s -> !s.equals("study")), anyInt(), anyInt()))
.thenReturn(new RsData<>("S-1", "성공", new ArrayList<>()));
📍when 절에서 조건문 만들기
@BeforeEach
void beforeEach() {
MemberResDto dto = new MemberResDto("test123");
when(memberClient.findById(any()))
.thenAnswer(invocation -> {
Long memberId = (Long) invocation.getArgument(0);
if (memberId == 2L)
return new RsData<>("S-1", "성공", dto);
else if (memberId == 3L)
throw new BadRequestException();
dto.setBaekJoonName("test123");
return new RsData<>("S-1", "성공", dto);
});
}