엄코딩의 개발 일지

Mockito를 이용한 UI 테스트 코드

 

Mockito는 유닛 테스트를위한 Java mocking framework 입니다. Mockito를 사용하여 쉽게 Mock Object를 만들어 관리할 수 있습니다.

 

Mock에 대한 개념은 아래 링크에서 자세하게 설명하고 있습니다.

 

Mock Object

 

Mock Object란 무엇인가? - Yoo Young-mo - Medium

다른 누군가로부터 휴대 전화 서비스(CellphoneService) 기능을 제공 받아 이를 사용한 휴대 전화 문자 발신기(CellphoneMmsSender)를 프로그래밍 한다고 생각해 보자.

medium.com

이 포스팅의 목적

 

제가 제일 처음 안드로이드 유닛 테스트 예제 코드를 작성하는 것 부터 이번 포스팅까지,

 

테스트를 접해보지 못하신분들, 도무지 어떻게 시작해야할지 모르는 분들에게 유익한 포스팅이 되었으면 좋겠습니다.

 

저도 구글링하면서 테스트를 실제 프로젝트에 도입해보기 위해 공부하며 정리한 포스팅인만큼, 충분히 쉽게 이해하실 수 있을겁니다!

 

그리고 시작했으면 끝을 봐야겠죠!

 

build.gradle

apply plugin: 'com.android.application'

apply plugin: 'kotlin-android'

apply plugin: 'kotlin-android-extensions'

android {
    compileSdkVersion 28
    defaultConfig {
        applicationId "com.example.mockitotest"
        minSdkVersion 24
        targetSdkVersion 28
        versionCode 1
        versionName "1.0"
        testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
    }
    buildTypes {
        release {
            minifyEnabled false
            proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
        }
    }
}

dependencies {
    implementation fileTree(dir: 'libs', include: ['*.jar'])
    implementation"org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version"
    implementation 'com.android.support:appcompat-v7:28.0.0'
    implementation 'com.android.support.constraint:constraint-layout:1.1.3'

    testImplementation 'junit:junit:4.12'
    testImplementation 'org.mockito:mockito-core:2.28.2'

    androidTestImplementation 'com.android.support.test:runner:1.0.2'
    androidTestImplementation 'com.android.support.test.espresso:espresso-core:3.0.2'
}

 

Person.kt

 data class Person(var name : String, var age : Int)

 

MockTest.kt

import junit.framework.Assert.assertEquals
import junit.framework.Assert.assertTrue
import org.junit.Test
import org.mockito.Mockito.`when`
import org.mockito.Mockito.mock

class MockTest{
    @Test
    fun test(){

        val p : Person = mock(Person::class.java)
        assertTrue(p != null)

        `when`(p.name).thenReturn("Seonoh")
        `when`(p.age).thenReturn(28)

        assertEquals(p.name,"Seonoh")
        assertEquals(p.age,28)
    }
}

 

코틀린에서는 when 구문이 존재해서인지 `when`으로 표기됩니다.

 

해당 구문을 통해서 stubbing을 제공합니다. 즉, 여기서는 thenReturn("Seonoh")를 통해서 Person의 name에 "Seonoh"를 

 

여기서 stubbing란 무엇일까 많이 들어봤지만 정확한 뜻은 무엇일까요?

 

아래 링크를 통해서 차근차근 이해해보면 좋을 것 같습니다. ( 저는 '정해진 질문에 대해 사전에 준비한 답' 이 와닿았습니다. )

 

테스트 스텁

실행결과

org.mockito.exceptions.base.MockitoException: 
Cannot mock/spy class com.example.mockitotest.Person
Mockito cannot mock/spy because :
 - final class

???

 

실행하자마자 겪은 에러입니다.

 

위 에러의 이유는 Mockito mock에서는 일반적으로 인스턴스를 만들기 위해 요청 클래스들을 확장합니다.

 

하지만 코틀린의 모든 클래스들은 default로 final 클래스로 정의됩니다. 

 

그래서 Mockito 라이브러리에서는 해당 클래스들을 확장할 수가 없는 것입니다.

 

해결방법

open을 사용하여 해결할 수도 있지만 개발자의 디자인 아키텍쳐와 맞지 않을 수 있기 때문에 dependency를 설정해주면됩니다.

 

testImplementation 'org.mockito:mockito-inline:2.8.47'