Last active
August 26, 2021 12:47
-
-
Save dariush-fathie/8cbd880b4ab04628f7b1c855bc69f2a6 to your computer and use it in GitHub Desktop.
Testable viewModel
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
interface DispatcherProvider { | |
val mainImmediate: CoroutineDispatcher | |
val io: CoroutineDispatcher | |
val default: CoroutineDispatcher | |
val unconfined: CoroutineDispatcher | |
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
@Singleton | |
class DispatcherProviderImpl @Inject constructor() : DispatcherProvider { | |
override val mainImmediate: CoroutineDispatcher | |
get() = Dispatchers.Main.immediate | |
override val io: CoroutineDispatcher | |
get() = Dispatchers.IO | |
override val default: CoroutineDispatcher | |
get() = Dispatchers.Default | |
override val unconfined: CoroutineDispatcher | |
get() = Dispatchers.Unconfined | |
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
open class BaseViewModel(dispatcherProvider: DispatcherProvider) : ViewModel(), | |
DispatcherProvider by dispatcherProvider | |
@HiltViewModel | |
class MainViewModel @Inject constructor( | |
dispatcherProvider: DispatcherProvider | |
) : BaseViewModel(dispatcherProvider) { | |
var isSaved = false | |
fun saveDataOnIO() { | |
onIO { | |
delay(5000) | |
isSaved = true | |
} | |
} | |
var isSessionExpired = false | |
fun checkSessionExpired(){ | |
onMain { | |
delay(10000) | |
isSessionExpired = true | |
} | |
} | |
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
class MainViewModelTest { | |
@ExperimentalCoroutinesApi | |
@get:Rule | |
var mainCoroutineRule = MainCoroutineRule() | |
@ExperimentalCoroutinesApi | |
val mainViewModel = MainViewModel( | |
TestDispatchersProvider(mainCoroutineRule.testCoroutineDispatcher) | |
) | |
@ExperimentalCoroutinesApi | |
@Test | |
fun saveDataOnIODispatcher() { | |
mainCoroutineRule.runBlockingTest { | |
mainViewModel.saveDataOnIO() | |
advanceUntilIdle() | |
assertTrue(mainViewModel.isSaved) | |
} | |
mainCoroutineRule.testCoroutineDispatcher.cleanupTestCoroutines() | |
} | |
@ExperimentalCoroutinesApi | |
@Test | |
fun `session must be expired after 10 seconds`() { | |
mainCoroutineRule.runBlockingTest { | |
mainViewModel.checkSessionExpired() | |
advanceUntilIdle() | |
assertTrue(mainViewModel.isSessionExpired) | |
} | |
mainCoroutineRule.testCoroutineDispatcher.cleanupTestCoroutines() | |
} | |
} | |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
inline fun BaseViewModel.onMain( | |
crossinline body: suspend CoroutineScope.() -> Unit | |
): Job { | |
// by default, Dispatchers.Main is default dispatcher to viewModelScope | |
return viewModelScope.launch() { | |
body(this) | |
} | |
} | |
inline fun BaseViewModel.onMainImmediate( | |
crossinline body: suspend CoroutineScope.() -> Unit | |
): Job { | |
// make sure to read documentation about immediate dispatcher, it can throw Exception! | |
return viewModelScope.launch(mainImmediate) { | |
body(this) | |
} | |
} | |
inline fun BaseViewModel.onIO( | |
crossinline body: suspend CoroutineScope.() -> Unit | |
): Job { | |
return viewModelScope.launch(io) { | |
body(this) | |
} | |
} | |
inline fun BaseViewModel.onDefault( | |
crossinline body: suspend CoroutineScope.() -> Unit | |
): Job { | |
return viewModelScope.launch(default) { | |
body(this) | |
} | |
} | |
inline fun BaseViewModel.onUnconfined( | |
crossinline body: suspend CoroutineScope.() -> Unit | |
): Job { | |
return viewModelScope.launch(unconfined) { | |
body(this) | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment