본문 바로가기

OS/Android

Android 유닛 테스트

반응형

유닛 테스트란?

유닛 테스트는 소스 코드의 특정 모듈이 의도된 대로 정확히 작동하는지 검증하는 절차이다.

즉, 모든 함수와 메소드에 대한 테스트 케이스를 작성하는 절차를 말한다.

안드로이드 유닛 테스트 종류

1. UI 테스트

- 하드웨어 기기나 에뮬레이터에서 실행되는 테스트이다.

- Context로 안드로이드 내부 API에 엑세스할 수 있다.

- 사용자 인터렉션을 평가하는 방식이다.

- 보통 Context가 필요한 테스트가 필요할 때 사용된다.

- 관련 툴 : Espresso, UIAutomator, Robotium, Appium, Calabash, Robolectric

 

2. Unit 테스트

- 일반적으로 코드의 유닛 단위(메소드, 클래스, 컴포넌트)의 기능을 실행하는 방식이다.

- 관련 툴 : JUnit, Mockito, PowerMock

유닛 테스트 작성

안드로이드 스튜디오로 프로젝트를 생성하게 되면 Gradle에 JUnit과 espresso 의존성이 추가되고 

테스트 패키지가 생성된다.

 

 

위 패키지 중에 (test)가 unit 테스트 영역이고 (androidTest)가 UI 테스트 영역이다.

각 영역에 테스트 코드를 작성해보도록 하겠다.

 

1. UI 테스트

MainActivity

package com.example.unittestsample

import android.content.Context
import android.graphics.Color
import androidx.appcompat.app.AppCompatActivity
import android.os.Bundle
import android.view.Gravity
import android.view.View
import android.view.ViewGroup
import android.widget.TextView
import androidx.databinding.DataBindingUtil
import com.example.unittestsample.databinding.ActivityMainBinding

class MainActivity : AppCompatActivity()
{
    private lateinit var m_binding : ActivityMainBinding
    
    override fun onCreate(savedInstanceState: Bundle?)
    {
        super.onCreate(savedInstanceState)
        m_binding = DataBindingUtil.setContentView(this, R.layout.activity_main)
        val arrTvList = createTextViewList(this@MainActivity, 50)
        m_binding.run {
            for (tv in arrTvList)
            {
                vLlTextContainer.addView(tv)
                vLlTextContainer.addView(createUnderLine(this@MainActivity))
            }
        }
    }

    fun createTextViewList(context : Context, nSize : Int) : List<TextView>
    {
        val arrTvList = mutableListOf<TextView>()
        for (i in 0..nSize)
        {
            val tv = TextView(context).apply {
                gravity = Gravity.CENTER
                textSize = 30f
                text = i.toString()
                setTextColor(Color.parseColor("#000000"))
            }
            arrTvList.add(tv)
        }
        return arrTvList
    }

    fun createUnderLine(context : Context) : View
    {
        return View(context).apply {
            layoutParams = ViewGroup.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, 1)
            setBackgroundColor(Color.parseColor("#000000"))
        }
    }
}

MainActivity를 실행하면 TextView와 UnderLine이 차례대로 생성된다.

MainActivity의 createTextView 함수가 제대로 작동하는지 확인해보도록 하겠다.

ExampleMainActivityTest

package com.example.unittestsample

import android.content.Context
import androidx.test.core.app.ActivityScenario
import androidx.test.platform.app.InstrumentationRegistry
import androidx.test.ext.junit.runners.AndroidJUnit4

import org.junit.Test
import org.junit.runner.RunWith

import org.junit.Assert.*
import org.junit.Before
import org.junit.Rule

/**
 * Instrumented test, which will execute on an Android device.
 *
 * See [testing documentation](http://d.android.com/tools/testing).
 */
@RunWith(AndroidJUnit4::class)
class ExampleMainActivityTest
{
    private lateinit var m_context : Context

    @Before
    fun useAppContext()
    {
        m_context = InstrumentationRegistry.getInstrumentation().targetContext
    }

    @Test
    fun isCheckTextViewCount()
    {
        ActivityScenario.launch(MainActivity::class.java).onActivity {
            val nSize = 50
            val arrTv = it.createTextViewList(m_context, nSize)
            assertEquals(nSize, arrTv.size)
        }
    }
}

@Before은 @Test 어노테이션보다 먼저 실행 할 수 있는 어노테이션이다.

그 외에도 @After, @BeforeClass 등 다양한 어노테이션이 있으니 따로 확인해보는 것을 추천한다.

 

assertEquals는 첫번째 파라미터가 기대값, 두번째 파라미터가 실제값을 의미하는 함수이다.

기대값이 실제값과 다를때는 다음과 같은 에러가 발생한다.

기대값과 실제값을 같게 만들어주기 위해 위 코드의 assertEquals(nSize, arrTv.size -1)로 고쳐주고 실행을 하게 되면

에러없이 테스트가 정상적으로 종료된다.

나는 UI 테스트로 Context에 접근할 수 있기 때문에 UI뿐 만 아니라 Local DB 테스트할 때 많이 사용한다.

 

 

2. Unit 테스트(JUnit 사용)

Unit 테스트는 모듈화한 클래스에서 많이 사용한다.

객체 리스트 클래스에서 Comparator 클래스를 사용하여 오름차순, 내림차순 정렬을 구현해 볼 것이다.

MyDataList

package com.example.unittestsample

import java.util.*
import kotlin.collections.ArrayList

class MyDataList : ArrayList<MyDataList.MyData>()
{
    fun sortByDesc()
    {
        Collections.sort(this, MyComparator(true))
    }

    fun sortByAsc()
    {
        Collections.sort(this, MyComparator(false))
    }

    inner class MyComparator(val desc : Boolean) : Comparator<MyData>
    {
        override fun compare(lhs: MyData, rhs: MyData): Int
        {
            return compareInt(lhs.id, rhs.id)
        }

        fun compareInt(a1: Int, a2: Int): Int
        {
            if (desc)
            {
                if (a1 > a2)
                    return 1
            }
            else
            {
                if (a1 < a2)
                    return 1
            }
            return if (a1 == a2) 0 else -1
        }
    }

    data class MyData(
        val id : Int,
        val name : String
    )
}

sortByDesc와 sortByAsc 함수가 제대로 작동하는지 테스트 해보기 위해 ExampleMyDataTest 클래스를 만들겠다.

 

ExampleMyDataTest

package com.example.unittestsample

import org.junit.Test

import org.junit.Assert.*
import org.junit.Before

/**
 * Example local unit test, which will execute on the development machine (host).
 *
 * See [testing documentation](http://d.android.com/tools/testing).
 */
class ExampleMyDataTest
{
    private val m_arrData = MyDataList()
    private val m_nSize = 30
    @Before
    fun initData()
    {
        for (i in 0..m_nSize)
        {
            m_arrData.add(MyDataList.MyData(i, "$i is My Name"))
        }
    }

    @Test
    fun sort_my_data_list_desc_test()
    {
        m_arrData.shuffle()
        m_arrData.sortByDesc()

        assertEquals(4, m_arrData[0].id)
    }

    @Test
    fun sort_my_data_list_asc_test()
    {
        m_arrData.shuffle()
        m_arrData.sortByAsc()

        assertEquals(m_nSize, m_arrData[0].id)
    }
}

ExampleMyDataTest 파일을 실행해보면 다음과 같은 에러가 발생한다.

<Click to see difference> 링크를 클릭해보면

 

Expected와 Actual 값이 다른 것을 확인할 수 있다.

테스트 성공을 위해 sort_my_data_list_desc_test 함수에서 assertEquals(0, m_arrData[0].id)로 바꾸고 실행시켜 보겠다.

sort_my_data_list_desc_test

sort_my_data_list_asc_test 

두 함수 모두 테스트가 성공했다고 뜬다.

반응형

'OS > Android' 카테고리의 다른 글

안드로이드 패턴.. 어떤걸 쓰지??  (0) 2021.05.25
안드로이드 기존 버전 apk에서 -> 신규 버전 bundle로 업데이트  (0) 2021.04.08
Android Intent  (0) 2021.03.26
Android Context  (0) 2021.03.24
Android decompile  (0) 2021.03.10