Skip to content

Instantly share code, notes, and snippets.

Show Gist options
  • Save fernandospr/c5bffbb7e179d27e4272211471d08325 to your computer and use it in GitHub Desktop.
Save fernandospr/c5bffbb7e179d27e4272211471d08325 to your computer and use it in GitHub Desktop.
LiveData+ViewModel+RxJava+LCE+Action+UnitTests
sealed class SampleAction {
object Action1 : SampleAction()
data class Action2WithParams(val param1: String, val param2: String) : SampleAction()
}
sealed class SampleResource {
object Loading : SampleResource()
object Error : SampleResource()
data class Success(val resource: MyResource) : SampleResource()
}
data class MyResource(val id: String)
class SampleViewModel : ViewModel() {
private val _resource = MutableLiveData<SampleResource>()
private val _action = SingleLiveEvent<SampleAction>()
private val composite = CompositeDisposable()
override fun onCleared() = composite.clear()
fun getResource(): LiveData<SampleResource> = _resource
fun getAction(): LiveData<SampleAction> = _action
fun fetchResource() {
_resource = SampleResource.Loading
composite.add(
someObservable
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribeBy(
onSuccess = { _resource.value = SampleResource.Success(MyResource("Fernando")) }
onError = { _resource.value = SampleResource.Error }
)
)
}
fun operationResultingInAction() {
if (someLogic) {
_action.value = SampleAction.Action1
} else {
_action.value = SampleAction.Action2WithParams("PARAM1", "PARAM2")
}
}
}
class SampleActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
...
viewModel.getResource().observe(this, Observer {
handleResource(it)
})
viewModel.getAction().observe(this, Observer {
handleAction(it)
})
}
private fun handleResource(it: SampleResource) {
when (it) {
is SampleResource.Loading -> showLoading()
is SampleResource.Error -> showError()
is SampleResource.SuccessWithParams -> showSuccess(it.resource)
}
}
private fun handleAction(it: SampleAction) {
when (it) {
is SampleAction.Action1 -> performAction1()
is SampleAction.Action2WithParams -> performAction2(it.param1, it.param2)
}
}
}
class SampleUnitTest {
@get:Rule
val rule = InstantTaskExecutorRule()
@get:Rule
val rxRule = RxSchedulerRule()
private lateinit var viewModel: SampleViewModel
private lateinit var actionObserver: Observer<SampleAction>
private lateinit var resourceObserver: Observer<SampleResource>
@Before
fun setup() {
actionObserver = mock()
resourceObserver = mock()
viewModel = SampleViewModel()
viewModel.getAction().observeForever(actionObserver)
viewModel.getResource().observeForever(resourceObserver)
}
@Test
fun fetchResource_shouldShowLoading() {
viewModel.fetchResource(...)
val expected = SampleResource.Loading
verify(resourceObserver).onChanged(eq(expected))
}
@Test
fun fetchResource_shouldShowSuccess() {
viewModel.fetchResource(...)
val expected = SampleResource.SuccessWithParams(MyResource("Fernando"))
verify(resourceObserver).onChanged(eq(expected))
}
@Test
fun fetchResource_shouldShowError() {
viewModel.fetchResource(...)
val expected = SampleResource.Error
verify(resourceObserver).onChanged(eq(expected))
}
@Test
fun operation_shouldResultInAction1() {
viewModel.operationResultingInAction(...)
val expected = SampleAction.Action1
verify(actionObserver).onChanged(eq(expected))
}
@Test
fun operation_shouldResultInAction2() {
viewModel.operationResultingInAction(...)
val expected = SampleAction.Action2WithParams("Hello", "World")
verify(actionObserver).onChanged(eq(expected))
}
}
class RxSchedulerRule : TestRule {
private val scheduler by lazy { Schedulers.trampoline() }
override fun apply(base: Statement?, description: Description?): Statement =
object : Statement() {
override fun evaluate() {
try {
RxJavaPlugins.setComputationSchedulerHandler { scheduler }
RxJavaPlugins.setIoSchedulerHandler { scheduler }
RxJavaPlugins.setNewThreadSchedulerHandler { scheduler }
RxJavaPlugins.setSingleSchedulerHandler { scheduler }
RxAndroidPlugins.setInitMainThreadSchedulerHandler { scheduler }
base?.evaluate()
} finally {
RxJavaPlugins.reset()
RxAndroidPlugins.reset()
}
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment