web-dev-qa-db-ja.com

コルーチン-単体テストのviewModelScope.launchメソッド

ViewModelの単体テストを作成していますが、テストの実行に問題があります。 _runBlocking { ... }_ブロックは、実際には内部のコードが完了するのを待機していません。これは私には驚くべきことです。

resultnullであるため、テストは失敗します。なぜ_runBlocking { ... }_は、ブロックモデルでViewModel内でlaunchブロックを実行しないのですか?

asyncオブジェクトを返すDeferredメソッドに変換するかどうかがわかっているので、await()を呼び出してオブジェクトを取得するか、Jobを呼び出し、join()を呼び出します。 しかし、ViewModelメソッドをvoid関数のままにしてこれを実行したいのですが、これを行う方法はありますか?

_// MyViewModel.kt

class MyViewModel(application: Application) : AndroidViewModel(application) {

    val logic = Logic()
    val myLiveData = MutableLiveData<Result>()

    fun doSomething() {
        viewModelScope.launch(MyDispatchers.Background) {
            System.out.println("Calling work")
            val result = logic.doWork()
            System.out.println("Got result")
            myLiveData.postValue(result)
            System.out.println("Posted result")
        }
    }

    private class Logic {
        suspend fun doWork(): Result? {
          return suspendCoroutine { cont ->
              Network.getResultAsync(object : Callback<Result> {
                      override fun onSuccess(result: Result) {
                          cont.resume(result)
                      }

                     override fun onError(error: Throwable) {
                          cont.resumeWithException(error)
                      }
                  })
          }
    }
}
_
_// MyViewModelTest.kt

@RunWith(RobolectricTestRunner::class)
class MyViewModelTest {

    lateinit var viewModel: MyViewModel

    @get:Rule
    val rule: TestRule = InstantTaskExecutorRule()

    @Before
    fun init() {
        viewModel = MyViewModel(ApplicationProvider.getApplicationContext())
    }

    @Test
    fun testSomething() {
        runBlocking {
            System.out.println("Called doSomething")
            viewModel.doSomething()
        }
        System.out.println("Getting result value")
        val result = viewModel.myLiveData.value
        System.out.println("Result value : $result")
        assertNotNull(result) // Fails here
    }
}

_
11
Prem

私はトップアンサーを試してみましたが、すべての起動をやり直して、ディスパッチャ参照をメインまたは制限なしでテストに追加したくありませんでした。そのため、このコードをベーステストクラスに追加しました。私はメインのディスパッチャーを制限されていないものとして定義しています

private val testingDispatcher = Dispatchers.Unconfined

@BeforeEach
private fun doBeforeEach() {
    Dispatchers.setMain(testingDispatcher)
}

@AfterEach
private fun doAfterEach() {
    Dispatchers.resetMain()
}

私の場合、Flowを使用していて、これをLiveDataに切り替えました。単体テストでobserveForeverを実装することができ、ブレークポイントが内部で停止しました。それの。

0
Juan Mendez