IT Bookstore 과제 #14 - 실행 중인 API 중지 (4)

화면 종료시 실행 중인 API를 중지하기 위해서는 CompositeDisposable 객체의 clear() 또는 dispose() 함수를 실행하는 것입니다. 이 객체는 BaseViewModel 클래스 안에 정의하였으며, 그것의 onClear() 함수를 오버라이드(override)하여 CompositeDisposable 객체의 clear() 또는 dispose() 함수를 호출시킵니다. 이를 코드로 나타내면 다음과 같습니다.

open class BaseViewModel : ViewModel() {

    protected val disposables = CompositeDisposable()

    // ...

    override fun onCleared() {
        disposables.dispose()
        super.onCleared()
    }
}

어제 작성한 테스트 코드가 실패하는 원인 그리고 해결

  • 테스트 대상 클래스, 필드, 메소드: BookSearchViewModel, disposables, onCleared
  • 테스트 클래스, 메소드: BookSearchViewModelTest, onCleared
  • 원인: disposables 필드는 private 멤버이며, 이에 접근하기 위해 reflection을 사용했으나, BookSearchViewModel 클래스로는 접근 불가
  • 해결: BookSearchViewModel 대신 BaseViewModel 클래스를 통해 disposables 멤버에 접근

수정한 테스트 코드

class BookSearchViewModelTest {

    // 라이브 데이터 테스트 하려면, 이 객체가 있어야 한다.
    // 참고 링크 - https://jeroenmols.com/blog/2019/01/17/livedatajunit5/
    @Rule
    @JvmField
    val instantExecutorRule = InstantTaskExecutorRule()

    lateinit var viewModel: BookSearchViewModel

    @Before
    fun setUp() {
        viewModel = BookSearchViewModel()
    }

    // ...

    @Test
    fun onCleared() {
        viewModel.searchBooks("android")
        Thread.sleep(Const.COMMON_DELAY_MILLISECONDS.toLong())

        BookSearchViewModel::class.java.declaredMethods.first {
            it.name == "onCleared"
        }?.let {
            it.isAccessible = true
            it.invoke(viewModel)
        }

        BaseViewModel::class.java.declaredFields.first {
            it.name == "disposables"
        }?.let {
            it.isAccessible = true

            val disposables = it.get(viewModel) as CompositeDisposable
            Assert.assertEquals(0, disposables.size())
        }
    }

}

마치며...

이번 단위 테스트를 통해 reflection을 사용해보았으나, 아직 낯설다는 느낌입니다. 이에 대해 좀 더 공부를 해볼 필요성을 느꼈습니다. 내일은 이에 대한 내용을 정리하고 샘플 코드를 만들어 보겠습니다.


지난 IT Bookstore 과제

Coin Marketplace

STEEM 0.18
TRX 0.13
JST 0.029
BTC 57452.21
ETH 3016.39
USDT 1.00
SBD 2.36