본문 바로가기
TDD/Android TDD

Android TDD 실전편 -1

by startSW 2023. 10. 11.

Android App 프로젝트에 TDD로 In-app Update 기능을 추가해보겠습니다.

 

이전의 Unit Test 방법에 대한 글을 참고하시면 더 쉽게 이해가 가능합니다.

https://swjsw.tistory.com/21

 

[Android] Unit Test 작성하기 -1

아래 글은 이전에 작성한 ViewModel 클래스를 참고로 작성되었습니다. https://swjsw.tistory.com/20 [Android] Livedata 사용하기 아래 글은 이전에 작성한 ViewModel 클래스를 참고하여 작성 되었습니다. https://swj

swjsw.tistory.com

 

 

1. 먼저 아래와 같이 테스트 하고자 하는 함수의 이름을 기반으로 테스트 함수를 작성합니다.

determineUpdateType() 함수는 아직 ViewModel에 추가하지 않은 상태이고, 파라미터도 임의로 만들었습니다.

지금 중요한 것은 테스트 하고자 하는 함수 즉 기능인 것입니다.

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

    private lateinit var viewModel: FlashlightViewModel

    @Before
    fun setup() {
        viewModel = FlashlightViewModel()

    }

    @Test
    fun testDetermineUpdateType() {
        assertEquals(1, viewModel.determineUpdateType(1, 2))
    }

}

 

2. Test함수가 만들어 졌으니 이제 VewModel에 determineUpdateType() 함수를 추가합니다.

무조건 1을 리턴하도록 작성했습니다.

fun determineUpdateType(oldVersion: Int, newVersion: Int): Int {
    return 1
}

유닛 테스트를 실행하면 당연히 잘 통과하는 것을 볼 수 있습니다.

 

3. 이제 determineUpdateType() 함수의 인자와 리턴 타입을 실제로 사용하는 것으로 변경합니다.

determineUpdateType() 함수의 리턴 타입은 Int로 유지합니다.

determineUpdateType() 함수의 인자는 아래와 같이 실제로 필요한 인자들로 변경합니다.

그리고 함수를 AppUpdateType.*IMMEDIATE*를 리턴하도록 수정합니다.

이 값은 1 입니다.

 fun determineUpdateType(updatePriority: Int, clientVersionStalenessDays: Int, immediateUpdateTypeAllowed: Boolean, flexibleUpdateTypeAllowed: Boolean): Int {
      return AppUpdateType.IMMEDIATE
  }

 

4. 테스트 코드도 통과 할 수 있도록 아래와 같이 수정합니다.

@Test
fun testDetermineUpdateType() {
    assertEquals(AppUpdateType.IMMEDIATE, viewModel.determineUpdateType(1, 2, true, true))
}

유닛테스트를 실행해서 통과 되는 것을 확인합니다.

 

5. 이제 determineUpdateType() 함수의 비지니스 로직을 작성합니다.

fun determineUpdateType(updatePriority: Int, clientVersionStalenessDays: Int, immediateUpdateTypeAllowed: Boolean, flexibleUpdateTypeAllowed: Boolean): Int {
    when {
        updatePriority == 5 -> {
            return if (immediateUpdateTypeAllowed) AppUpdateType.IMMEDIATE else -5
        }
        updatePriority == 4 -> {
            return if (immediateUpdateTypeAllowed) {
                if (clientVersionStalenessDays >= 5) {
                    AppUpdateType.IMMEDIATE
                } else {
                    AppUpdateType.FLEXIBLE
                }
            } else if (flexibleUpdateTypeAllowed) {
                AppUpdateType.FLEXIBLE
            } else -4
        }
        updatePriority == 3 -> {
            return if (immediateUpdateTypeAllowed) {
                if (clientVersionStalenessDays >= 7) {
                    AppUpdateType.IMMEDIATE
                } else {
                    AppUpdateType.FLEXIBLE
                }
            } else if (flexibleUpdateTypeAllowed) {
                AppUpdateType.FLEXIBLE
            } else -3
        }
        updatePriority == 2 -> {
            return if (immediateUpdateTypeAllowed) {
                if (clientVersionStalenessDays >= 14) {
                    AppUpdateType.IMMEDIATE
                } else {
                    AppUpdateType.FLEXIBLE
                }
            } else if (flexibleUpdateTypeAllowed) {
                AppUpdateType.FLEXIBLE
            } else -2
        }
        updatePriority == 1 -> {
            return -1
        }
        else -> {
            return -1
        }
    }
}

 

6. 테스트 코드를 updatePriority 값이 5인 경우에 대한 테스트로 수정하고 실행합니다.

@Test
fun testDetermineUpdateType() {
    assertEquals(AppUpdateType.IMMEDIATE, viewModel.determineUpdateType(5, 2, true, true))
}

 

 

7. updatePriority 값이 5이고, immediateUpdateTypeAllowed 값이 false 인 경우에 -5값이 리턴되기를 기대하는 테스트 코드를 추가합니다.

@Test
fun testDetermineUpdateType() {
    assertEquals(AppUpdateType.IMMEDIATE, viewModel.determineUpdateType(5, 2, true, true))
    assertEquals(-5, viewModel.determineUpdateType(5, 2, false, true))
}

 

8. 이제 모든 테스트 케이스를 추가합니다.

이 때 미처 생각지 못한 테스트 케이스가 있을 수 있지만 그런 테스트 케이스는 추후 QA 기간에 찾아질 수 있고, 그 때 추가하면 됩니다.

너무 모든 테스트 케이스를 작성해야 한다는 스트레스는 받지 않아도 됩니다.

@Test
fun testDetermineUpdateType() {
    assertEquals(AppUpdateType.IMMEDIATE, viewModel.determineUpdateType(5, 2, true, true))
    assertEquals(-5, viewModel.determineUpdateType(5, 2, false, true))

    assertEquals(AppUpdateType.IMMEDIATE, viewModel.determineUpdateType(4, 5, true, true))
    assertEquals(AppUpdateType.FLEXIBLE, viewModel.determineUpdateType(4, 2, true, true))
    assertEquals(AppUpdateType.FLEXIBLE, viewModel.determineUpdateType(4, 2, false, true))
    assertEquals(-4, viewModel.determineUpdateType(4, 2, false, false))

    assertEquals(AppUpdateType.IMMEDIATE, viewModel.determineUpdateType(3, 7, true, true))
    assertEquals(AppUpdateType.FLEXIBLE, viewModel.determineUpdateType(3, 2, true, true))
    assertEquals(AppUpdateType.FLEXIBLE, viewModel.determineUpdateType(3, 2, false, true))
    assertEquals(-3, viewModel.determineUpdateType(3, 2, false, false))

    assertEquals(AppUpdateType.IMMEDIATE, viewModel.determineUpdateType(2, 14, true, true))
    assertEquals(AppUpdateType.FLEXIBLE, viewModel.determineUpdateType(2, 2, true, true))
    assertEquals(AppUpdateType.FLEXIBLE, viewModel.determineUpdateType(2, 2, false, true))
    assertEquals(-2, viewModel.determineUpdateType(2, 2, false, false))

    assertEquals(-1, viewModel.determineUpdateType(1, 30, true, true))
    assertEquals(-1, viewModel.determineUpdateType(6, 30, true, true))
    assertEquals(-1, viewModel.determineUpdateType(-1, 30, true, true))
}

 

 

 

이로써 TDD 로 determineUpdateType 함수를 만들어 보았습니다.

이 함수를 이용하는 실제 기능은 다음 글에서 작성해 보겠습니다.