[Android TDD CodeLab 01. Testing Basics] part1

나고수·2022년 10월 16일
0

codelab

목록 보기
1/5

Android TDD CodeLab 01. Testing Basics Task. 1~7

Task: Running tests

source sets - 앱의 소스 코드가 포함된 폴더

  • main: 앱 코드를 포함합니다. 이 코드는 빌드할 수 있는 앱의 다른 모든 버전 간에 공유됩니다(Build Variants이라고 함).
    Build Variants = BuildType (디버그, 릴리즈 등) + Product Flavor (무료버전, 유료버전 등) 을 조합해 여러 버전의 앱을 만드는 것.
  • androidTest: 계측 테스트로 알려진 테스트를 포함합니다.
  • test: 로컬 테스트로 알려진 테스트를 포함합니다.

로컬 테스트 vs 계측 테스트

  • 로컬 테스트(test source set)
    이러한 테스트는 개발 머신의 JVM에서 로컬로 실행되며 에뮬레이터나 물리적 장치가 필요하지 않습니다. 빠르지만 충실도(fidelity)가 낮아 실제 작동 방식과 차이가 있을 수 있습니다.
class ExampleUnitTest {
    @Test
    fun addition_isCorrect() {
        assertEquals(4, 2 + 2)
    }
}
  • 계측 테스트(androidTest source set)
    이러한 테스트는 실제 또는 에뮬레이트된 Android 기기에서 실행되므로 실제 작동 방식을 반영하지만 속도가 느립니다.
//계측 테스트는 거의 항상 Android OS 또는 Android 프레임워크를 사용합니다. 
//InstrumentationRegistry를 사용하여 context를 얻어서 패키지 이름을 테스트 하기 때문에 계측 테스트로 테스트 해야 합니다. 
@RunWith(AndroidJUnit4::class)
class ExampleInstrumentedTest {
    @Test
    fun useAppContext() {
        // Context of the app under test.
        val appContext = InstrumentationRegistry.getInstrumentation().targetContext
        assertEquals("com.example.android.architecture.blueprints.reactive",
            appContext.packageName)
    }
}

Task: Writing your first test

테스트 만드는 법

  1. 원본 코드에서 command + n 을 누른다.
  2. 로컬/계측 테스트에 따라 test / android test 위치를 고른 후 생성

함수 이름 짓는 법

  • 테스트중인 메서드or클래스___작업____예상결과
  • ex) getActiveAndCompletedStats_noCompleted_returnsHundredZero()
  • 테스트 중인 메서드_완료된 작업 없을 때_100,0을 리턴할 것이다.

Hamcrest 종속성 추가

  • testImplementation "org.hamcrest:hamcrest-all:$hamcrestVersion"
  • Hamcrest라는 assertion 프레임워크를 사용
  • Junit의 assertion 보다 사람이 읽기 편하다.
  • 다른 assertion 프레임워크는 Truth 가 있다.
//Junit.assertion
assertEquals(result.activeTasksPercent,100f)
assertEquals(result.completedTasksPercent,0f)

//Hamcrest - 가독성이 더 좋음 
//is 에 뒷따옴표가 있는 이유?
//코틀린에서 이미 is는 예약어이다. 
//따라서 hamcrest에서 뒷따옴표를 붙여서 코틀린의 is와 구별한다.

assertThat(result.activeTasksPercent, `is`(100f))
assertThat(result.completedTasksPercent, `is`(0f))

종속성 추가

  • 앱의 테스트 코드나 종속 항목으로 인해 APK 크기가 커지지 않는 것이 가장 좋습니다.
    • implementation — test source set을 포함한 모든 source set에서 종속성을 사용할 수 있습니다.
    • testImplementation — test source set에서만 종속성을 사용할 수 있습니다.
    • androidTestImplementation — androi test source set에서만 종속성을 사용할 수 있습니다.

읽기 쉬운 테스트를 작성하는 전략 - Given, When, Then

 @Test
    fun getActiveAndCompletedStats_noCompleted_returnsHundredZero() {

        // Create an active tasks (the false makes this active)
        val tasks = listOf<Task>(
            Task("title", "desc", isCompleted = false)
        )
        // Call your function
        val result = getActiveAndCompletedStats(tasks)

        // Check the result
        assertThat(result.activeTasksPercent, `is`(100f))
        assertThat(result.completedTasksPercent, `is`(0f))

    }
  • Given: 테스트에 필요한 객체와 앱 상태를 설정합니다.
    이 테스트에서 "Given"은 active된 작업 목록이 있다는 것입니다.
  • When: Do the actual action on the object you're testing.
    이 테스트의 경우 getActiveAndCompletedStats 호출을 의미합니다.
  • Then: assertion을 사용하여 테스트 통과 또는 실패 여부를 확인하는 작업을 수행합니다.
    이 테스트의 경우 올바른 active 및 completed 퍼센트가 나왔는지 확인하는 두가지 assertion입니다.

    "Arrange, Act, Assert"(AAA) test mnemonic과 유사한 개념입니다.

StatisticsUtilsTest.kt 에서 여러가지 테스트 해보기

package com.example.android.architecture.blueprints.todoapp.statistics

import com.example.android.architecture.blueprints.todoapp.data.Task
import org.hamcrest.MatcherAssert.assertThat
import org.hamcrest.core.Is.`is`
import org.junit.Test

class StatisticsUtilsTest {
    //함수 이름 짓는 법 :  테스트중인 메서드or클래스_작업_예상결과
    @Test
    fun getActiveAndCompletedStats_noCompleted_returnsHundredZero() {
        // Create an active task
        val task1 = Task("test1", "test1", false)
        val task2 = Task("test2", "test2", false)
        val list = listOf<Task>(task1, task2)
        // Call your function
        val result = getActiveAndCompletedStats(list)
        // Check the result
//        assertEquals(result.activeTasksPercent,100f)
//        assertEquals(result.completedTasksPercent,0f)

        assertThat(result.activeTasksPercent, `is`(100f))
        assertThat(result.completedTasksPercent, `is`(0f))
    }

    @Test
    fun getActiveAndCompletedStats_empty_returnsZeros() {
        // Create an active task
        val list = listOf<Task>()
        // Call your function
        val result = getActiveAndCompletedStats(list)
        // Check the result
        assertThat(result.activeTasksPercent, `is`(0f))
        assertThat(result.completedTasksPercent, `is`(0f))
    }

    @Test
    fun getActiveAndCompletedStats_noActive_returnsZeroHundred() {
        // Create an active task
        val task2 = Task("test2", "test2", true)
        val list = listOf<Task>(task2)
        // Call your function
        val result = getActiveAndCompletedStats(list)
        // Check the result
        assertThat(result.activeTasksPercent, `is`(0f))
        assertThat(result.completedTasksPercent, `is`(100f))
    }

    @Test
    fun getActiveAndCompletedStats_error_returnsZeros() {
        // Create an active task
        // Call your function
        val result = getActiveAndCompletedStats(null)
        // Check the result
        assertThat(result.activeTasksPercent, `is`(0f))
        assertThat(result.completedTasksPercent, `is`(0f))
    }

    @Test
    fun getActiveAndCompletedStats_both_returnsFortySixty() {
        // Create an active task
        val task1 = Task("test1", "test1", true)
        val task2 = Task("test2", "test2", true)
        val task3 = Task("test3", "test3", true)
        val task4 = Task("test4", "test4", false)
        val task5 = Task("test5", "test5", false)
        // Call your function
        val result = getActiveAndCompletedStats(listOf(task1, task2, task3, task4, task5))
        // Check the result
        assertThat(result.activeTasksPercent, `is`(40f))
        assertThat(result.completedTasksPercent, `is`(60f))
    }
}

TDD의 단계

  1. 테스트 작성
  2. (일부러 버그가 있는 테스트를 작성해서) 테스트가 실패했는지 확인합니다.
  3. 테스트를 통과하도록 최소한의 코드를 작성하십시오.
  4. 모든 테스트에 대해 반복하십시오!
  • 왜 테스트가 실패되도록 작성해야 하나요?
    테스트가 통과하도록 코드를 작성하지 않은 상태에서 테스트가 통과하면 이상한 일이 진행되고 있음을 알 수 있습니다.
    테스트가 항상 통과하거나(쓸모 없는 테스트임) 테스트가 올바른 코드를 사용하지 않을 수 있습니다.
  • 여기서는, taskList가 비어있거나(getActiveAndCompletedStats_empty_returnsZeros) 작업을 로드하는 중에 오류가 발생한 경우(getActiveAndCompletedStats_error_returnsZeros)두 퍼센트는 모두 0f여야 합니다.
profile
되고싶다

0개의 댓글