ViewModelの単体テストを作成していますが、テストの実行に問題があります。 _runBlocking { ... }
_ブロックは、実際には内部のコードが完了するのを待機していません。これは私には驚くべきことです。
result
はnull
であるため、テストは失敗します。なぜ_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
}
}
_
私はトップアンサーを試してみましたが、すべての起動をやり直して、ディスパッチャ参照をメインまたは制限なしでテストに追加したくありませんでした。そのため、このコードをベーステストクラスに追加しました。私はメインのディスパッチャーを制限されていないものとして定義しています
private val testingDispatcher = Dispatchers.Unconfined
@BeforeEach
private fun doBeforeEach() {
Dispatchers.setMain(testingDispatcher)
}
@AfterEach
private fun doAfterEach() {
Dispatchers.resetMain()
}
私の場合、Flow
を使用していて、これをLiveData
に切り替えました。単体テストでobserveForever
を実装することができ、ブレークポイントが内部で停止しました。それの。