[Mockito] ArgumentCaptor 사용해 객체의 interaction 기록하기

2022. 12. 21. 22:10·Unit Testing
반응형

ArgumentCaptor 란?

ArgumentCaptor란 interaction을 기록하는 Mock 타입의 Test Double을 만드는 객체이다. 즉, ArgumentCaptor은 객체의 interaction을 기록한다.

 

ArgumentCaptor 사용하기 위한 환경 설정

ArgumentCaptor을 사용하기 위해서 앞선 글 https://simcode.tistory.com/12 의 환경을 가져와서 LoginUseCase, LoginUseCaseResult, LoginRepository, LoginRepositoryResult를 사용한다. 환경 설정 부분을 읽도록 하자.

 

ArgumentCaptor 사용한 테스트 만들기

LoginUseCase의 logIn메서드에서 userName과 password변형이 생겨서 LoginRepository에 같은 userName과 password가 넘어가지 않았다면 문제가 생기는 상황이라 가정하자. 이런 상황에서는 LoginUseCase에서 특정한 userName과 password로 로그인을 시도했을 때 해당 파라미터가 LoginRepository로 잘 넘어갔는지 확인하는 테스트를 만들어야 한다.

 

변수 정의하기

먼저 userName과  password라는 변수를 만들고 token과 repositorySuccessResult를 미리 정의한다.

val userName = "test"
val password = "password"
val token = "test_token"
val repositorySuccessResult = LoginRepositoryResult.Success(token)

 

Stub 만들기

위에서 정의한 userName과 password로 로그인을 시도했을 때 respositorySuccessResult를  return하는 Stub을 생성한다.

*Stub: 특정한 요청에 미리 정의된 객체를 반환하는 Test Double 

Mockito.`when`(loginRepository.login(userName = userName, password = password))
    .thenReturn(repositorySuccessResult)

 

LoginUseCase에 로그인 요청하기

이제 LoginUseCase에 로그인을 요청하면 된다.

val result = loginUseCase.logIn(userName = userName, password = password)

 

ArgumentCaptor로 LoginRepository의 interaction 기록하기

LoginUseCase는 logIn요청 시 loginRepository에 logIn 요청을 넘긴다. 이때 useName, password  파라미터가 잘 넘어갔는지 ArgumentCaptor을 통해 기록해보자.

class LoginUseCase(
    private val loginRepository: LoginRepository
) {
    fun logIn(userName: String, password: String): LoginUseCaseResult {
        return when (val result = loginRepository.login(userName, password)) {
            is LoginRepositoryResult.Success -> LoginUseCaseResult.Success(result.token)
            is LoginRepositoryResult.Fail    -> LoginUseCaseResult.Success(result.error)
        }
    }
}

 

argumentCaptor을 선언하고 argumentCaptor<String>()을 통해 초기화 한 후 loginRepository의 logIn메서드가 1번 수행되고 해당 logIn 시 넘어간 userName과 password를 capture()메서드로 argumentCaptor에 기록 한다.

val argumentCaptor = argumentCaptor<String>()
Mockito.verify(loginRepository, times(1)).login(argumentCaptor.capture(), argumentCaptor.capture())

 

ArgumentCaptor검증하기

ArgumentCaptor은 allValues 호출 시 capture()한 모든 값을 순서대로 List로 반환한다.

val allValues: List<T>
    get() = captor.allValues

 

따라서 다음과 같이 사용하면 userName과 password가 제대로 입력되었는지 검증할 수 있다.

assertEquals(userName, argumentCaptor.allValues[0])
assertEquals(password, argumentCaptor.allValues[1])
assertEquals(LoginUseCaseResult.Success(token), result)

 

전체 코드

전체 코드는 다음과 같다. 앞 setUp()메서드는 이전 글에서 다룬 것과 같아서 이 글에서는 환경 설정에서 생략했다.

package lecture4

import org.junit.Assert.assertEquals
import org.junit.Before
import org.junit.Test
import org.mockito.Mockito
import org.mockito.Mockito.times
import org.mockito.kotlin.argumentCaptor

class LoginUseCaseArgumentCaptorTest {
    private lateinit var loginUseCase: LoginUseCase
    private lateinit var loginRepository: LoginRepository

    @Before
    fun setUp() {
        loginRepository = Mockito.mock(LoginRepository::class.java)
        loginUseCase = LoginUseCase(loginRepository)
    }

    @Test
    fun testLoginSuccessMockArgumentCaptor() {
        val userName = "test"
        val password = "password"
        val token = "test_token"
        val repositorySuccessResult = LoginRepositoryResult.Success(token)
        Mockito.`when`(loginRepository.login(userName = userName, password = password))
            .thenReturn(repositorySuccessResult)

        val result = loginUseCase.logIn(userName = userName, password = password)

        val argumentCaptor = argumentCaptor<String>()
        Mockito.verify(loginRepository, times(1)).login(argumentCaptor.capture(), argumentCaptor.capture())

        assertEquals(userName, argumentCaptor.allValues[0])
        assertEquals(password, argumentCaptor.allValues[1])
        assertEquals(LoginUseCaseResult.Success(token), result)
    }
}

 

정리

Test Double은 Test를 위해 필요한 3가지 유형 Mock, Stub, Fake을 가진다. ArgumentCaptor는 Mock 유형으로 객체의 Interaction을 기록하기 위한 객체이다. ArgumentCaptor을 사용하면 손쉽게 Interaction을 기록하고 테스트 할 수 있다.

 

*만약 Test Double에 대해 잘 모른다면, https://simcode.tistory.com/10 를 참고하자.

반응형

'Unit Testing' 카테고리의 다른 글

MockitoJUnitRunner 사용해 Mockito 코드 깔끔하게 만들기 : @Mock  (0) 2022.12.23
Kotlin에서 Mockito ArgumentCaptor 사용시 java.lang.NullPointerException: argumentCaptor.capture() must not be null 나오는 현상 해결 방법  (0) 2022.12.22
[Mockito] when 사용법 한 번에 정리하기 : thenReturn, thenAnswer, doThrow  (0) 2022.12.20
[Unit Testing] Mockito 사용해 Test Double 만들기  (0) 2022.12.19
Test Double이란 무엇인가? Test Double의 종류, 사용법 알아보기  (0) 2022.12.18


'Unit Testing' 카테고리의 다른 글
  • MockitoJUnitRunner 사용해 Mockito 코드 깔끔하게 만들기 : @Mock
  • Kotlin에서 Mockito ArgumentCaptor 사용시 java.lang.NullPointerException: argumentCaptor.capture() must not be null 나오는 현상 해결 방법
  • [Mockito] when 사용법 한 번에 정리하기 : thenReturn, thenAnswer, doThrow
  • [Unit Testing] Mockito 사용해 Test Double 만들기
심플코드
심플코드
프로그래밍을 어렵지 않게 풀어서 설명하는 기술 블로그
    반응형
  • 심플코드
    심플코드
    심플코드
  • 전체
    오늘
    어제
    • 분류 전체보기 (96)
      • 안드로이드를 위한 Coroutines (2)
      • Unit Testing (19)
      • GitHub Actions (0)
      • 공식 문서 번역 (35)
        • Coroutines 공식 문서 (35)
      • 알고리즘 (7)
        • Kotlin 자료구조 (0)
        • 알고리즘 (7)
        • Kotlin으로 구현하는 자료구조 (0)
      • 코딩 테스트 (0)
      • Deep Learning (0)
      • Machine Learning Math (17)
        • Linear Algebra (17)
      • ML (0)
      • Docker (15)
      • Kubernetes (1)
  • 블로그 메뉴

    • 홈
    • 태그
    • 방명록
  • 링크

  • 공지사항

    • 코틀린 코루틴의 정석 책 출간 소식
  • 인기 글

  • 태그

    코루틴
    컨테이너
    코루틴 채널
    Kotlin
    junit
    mockito
    도커
    코루틴 Flow
    unit testing
    Coroutines
    unit test
    TensorFlow
    Docker
    pytorch
    numpy
    Coroutines Channel
    coroutine
    Coroutines Context
    Coroutines Flow
    Machine Learning
  • 최근 댓글

  • 최근 글

  • hELLO· Designed By정상우.v4.10.3
심플코드
[Mockito] ArgumentCaptor 사용해 객체의 interaction 기록하기
상단으로

티스토리툴바