본문 바로가기
Android/Unit Test

[Android] Unit Test 작성하기 -5(Mockito-2)

by startSW 2023. 9. 27.

이전의 Mockito을 이용한 Unit Test 글에 이어 이번에는 좀 더 Mockito을 활용하는 방법을 알아보겠습니다.

 

1. 먼저 앱 모듈의 build.gradle 파일에 Mockito 의존성을 추가합니다.

 

    testImplementation("org.mockito:mockito-core:4.0.0")
    testImplementation("org.mockito:mockito-inline:2.21.0")
    testImplementation("com.nhaarman.mockitokotlin2:mockito-kotlin:2.2.0")

 

org.mockito:mockito-inline 라이브러리는 Final 클래스와 Spy 클래스(Mockito Kotlin 라이브러리를 사용할 때)를 모킹하기 위한 것이 주요 목적입니다. 파이널 클래스는 상속될 수 없고, 스파이 클래스는 Mockito Kotlin을 사용할 때 스파이화할 수 없는 클래스를 나타냅니다. 이러한 제약을 극복하고 모의 객체 또는 스파이 객체를 생성하기 위해 mockito-inline 라이브러리를 사용할 수 있습니다.

파이널 클래스 및 스파이 클래스를 모킹할 때 mockito-inline 라이브러리를 사용하면 Mockito가 내부적으로 ASM(Java 바이트 코드 조작 라이브러리)를 사용하여 모킹을 가능하게 합니다. 이를 통해 Mockito는 파이널 클래스와 스파이 클래스를 모킹하고 모의 객체를 생성할 수 있게 됩니다. 따라서 파이널 클래스나 스파이 클래스를 모킹해야 하는 경우 mockito-inline 라이브러리를 사용하여 Mockito의 능력을 확장할 수 있습니다.

따라서 파이널 클래스나 스파이 클래스를 모킹해야 하는 경우 mockito-inline 라이브러리를 사용하여 Mockito의 능력을 확장할 수 있습니다.

 

com.nhaarman.mockitokotlin2 라이브러리는 Mockito와 함께 Kotlin 언어에서 모의 객체를 생성하고 사용하는 데 도움을 주는 라이브러리입니다. 이 라이브러리를 사용하는 주요 이유와 장점은 다음과 같습니다:

  1. Kotlin과의 호환성: Kotlin은 Java와는 다른 언어이며, Mockito는 Java에 더 적합한 라이브러리입니다. Kotlin에서 기본 Mockito를 사용할 때 몇 가지 문법적 차이점과 제약 사항이 발생할 수 있습니다. com.nhaarman.mockitokotlin2 라이브러리는 Kotlin에서 Mockito를 더 편리하게 사용할 수 있도록 설계되었습니다. 따라서 Kotlin에서 Mockito를 사용하는 데 생기는 어려움을 줄일 수 있습니다.
  2. 더 간결한 문법: **com.nhaarman.mockitokotlin2**를 사용하면 Kotlin의 간결한 문법을 활용하여 모의 객체를 생성하고 설정할 수 있습니다. Kotlin의 확장 함수와 람다 표현식을 사용하여 테스트 코드를 더 읽기 쉽고 간결하게 작성할 수 있습니다.
  3. 코드 가독성 향상: Kotlin과 **com.nhaarman.mockitokotlin2**를 함께 사용하면 테스트 코드의 가독성이 향상됩니다. 예를 들어, Mockito를 사용하여 모의 객체를 생성하고 설정하는 코드가 더 간결하고 직관적으로 표현됩니다.

예를 들어, 기본 Mockito를 사용한 Java 코드:

javaCopy code
when(mockedList.add(anyString())).thenReturn(false);

**com.nhaarman.mockitokotlin2**를 사용한 Kotlin 코드:

kotlinCopy code
whenever(mockedList.add(any<String>())).thenReturn(false)

이처럼 Kotlin과 **com.nhaarman.mockitokotlin2**를 함께 사용하면 테스트 코드를 작성하기 더 쉽고 가독성 있게 만들 수 있습니다.

 

 

2. 테스트 코드를 작성합니다.

import androidx.arch.core.executor.testing.InstantTaskExecutorRule
import com.nhaarman.mockitokotlin2.whenever
import com.swjsw.app.cleanflashlight.common.util.FlashLightManager
import com.swjsw.app.cleanflashlight.flashlight.FlashlightViewModel
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.delay
import kotlinx.coroutines.test.UnconfinedTestDispatcher
import kotlinx.coroutines.test.resetMain
import kotlinx.coroutines.test.runTest
import kotlinx.coroutines.test.setMain
import org.junit.Assert.assertEquals
import org.junit.Before
import org.junit.Rule
import org.junit.Test
import org.mockito.Mock
import org.mockito.MockitoAnnotations

class FlashlightViewModelUnitTest {
    @get:Rule
    val rule = InstantTaskExecutorRule()

    @Mock
    lateinit var flashlightManager: FlashLightManager

    private lateinit var viewModel: FlashlightViewModel
    private lateinit var flashlightManagerListener: FlashlightViewModel.FlashlightViewModelListener

    @Before
    fun setup() {
        MockitoAnnotations.openMocks(this)

        viewModel = FlashlightViewModel()

        flashlightManagerListener = FlashlightViewModel.FlashlightViewModelListener(viewModel)

        whenever(flashlightManager.flashlightOn()).thenAnswer {
            flashlightManagerListener.onFlashLightOn()
        }

        whenever(flashlightManager.flashlightOff()).thenAnswer {
            flashlightManagerListener.onFlashLightOff()
        }

        whenever(flashlightManager.flashlightToggle()).thenAnswer {
            if (viewModel.isFlashlightOn.value == true) {
                flashlightManagerListener.onFlashLightOff()
            } else {
                flashlightManagerListener.onFlashLightOn()
            }
        }

        viewModel.setFlashlightManger(flashlightManager)
        viewModel.setFlashlightMangerListener(flashlightManagerListener)
    }

    @Test
    fun testTurnOnFlashlight() {
        viewModel.turnOnFlashlight()
        assertEquals(true, viewModel.isFlashlightOn.getOrAwaitValue())
    }

    @Test
    fun testTurnOffFlashlight() {
        viewModel.turnOffFlashlight()
        assertEquals(false, viewModel.isFlashlightOn.getOrAwaitValue())
    }
}

위 테스트 코드에서 FlashLightManager를 모킹하고 ‘whenever’ 를 사용해서 스터빙을 하고 있습니다.

“@Mock” 애노테이션과 “MockitoAnnotations.openMocks(this)” 을 이용해서 Mock 객체를 만드는 것을 볼 수 있습니다.