ViewModelを初期化しようとして`Module with the Main dispatcher had failed to initialize`というエラーが出た話
テスト時にViewModel
を初期化する処理を次のように書いた。
class LabelListViewModelTest { private val testScheduler = TestCoroutineScheduler() private val dispatcher = StandardTestDispatcher(testScheduler) private val repository = mockk<LabelRepository>(relaxed = true) private val sut = LabelListViewModel(repository) @Before fun setup() { Dispatchers.setMain(dispatcher) }
そしたら、次のようなエラーが発生した。
Exception in thread "Test worker" java.lang.IllegalStateException: Module with the Main dispatcher had failed to initialize. For tests Dispatchers.setMain from kotlinx-coroutines-test module can be used
ViewModel
の中身を確認してみる。
... @HiltViewModel class LabelListViewModel @Inject constructor( private val labelRepository: LabelRepository ) : ViewModel() { private val viewModelState = MutableStateFlow( LabelListViewModelState( isLoading = false, ) ) val uiState = viewModelState .map { it.toUiState() } .stateIn( viewModelScope, SharingStarted.Eagerly, viewModelState.value.toUiState() )
おそらく、setup()
でDispatchers.setMain()
を呼び出す前に、.stateIn(viewModelScope, SharingStarted.Eagerly, viewModelState.value.toUiState())
が呼び出されてしまっているためModule with the Main dispatcher had failed to initialize
というエラーが発生したのだと思う。
なのでlateinit
を使ってsetup()
の中でsut
を初期化するようにしたらエラーが消えた。
... @HiltViewModel class LabelListViewModel @Inject constructor( private val labelRepository: LabelRepository ) : ViewModel() { private val viewModelState = MutableStateFlow( LabelListViewModelState( isLoading = false, ) ) val uiState = viewModelState .map { it.toUiState() } .stateIn( viewModelScope, SharingStarted.Eagerly, viewModelState.value.toUiState() )