architecture-components-samples
architecture-components-samples copied to clipboard
Testability of UserViewModel
Hi! Thanks for the Rx + Kotlin + Room example @florina-muntenescu ! I was looking at the UserViewModel + Activity and found myself wondering how the testability could go further, specifically if we wanted so do something like ensuring that clicking the update button results in disabling it during the duration of the DB write.
Currently, the button is being disabled within the Activity code, but I thought moving this responsibility to the ViewModel would make it more easily testable.
interface UserViewModel {
// Still responsible of dictating the username text
fun userName(): Flowable<String>
// Dictates wether the button is clickable or not.
// (Could provide initial state with .startWith())
fun buttonState():Observable<Boolean>
//responsible with writing username updates,
//Observable<String> as parameter representing username text changes
//Observable<Any> representing button clicks.
fun updateUsername(changes:Observable<String>, clicks:Observable<Any>): Observable<Any>
/* Implementation connects input parameters with observable chain that
*1. Grabs the latest change value when a click is emitted
*2. Pushes false on buttonState stream to disable it
*3. Updates db with new username value
*4. Pushes true on buttonState stream to re-enable it */
}
Would you welcome this as an improvement?
As a general principle, your ViewModel should work even with a totally different UI operating on the same dataset. Otherwise it starts to become a god object. If you want to be able to unit test your UI logic, consider something like a Presenter.
@lukasb - Your ViewModel simply exposes data streams that contain pure information about what your View is supposed to display. It's the View's job to bind to those data streams, so if you were switching to a totally different UI - unless your new UI represents to same piece of information or a subset of it - Your ViewModel will change for sure, and that is not a bad thing at all.
Consider a situation where we would be designing a brand new View with the same expected functionality as above of disabling the update button when updating the database/api. If this logic was implemented on the View level, then it would need to be rewritten for your new View. If, however, the functionality was implemented by the ViewModel, your logic would be ready to be reused. Moreover, moving that logic on the ViewModel makes it testable without requiring a heavy instrumentation test.