ursus
08/18/2020, 8:24 PMJohn Leeroy
08/18/2020, 8:28 PMursus
08/18/2020, 8:33 PMviewModel.someAction()
viewModel.stateObservable.test().assertValue(...)
John Leeroy
08/18/2020, 8:37 PMsomeAction
and the acceptance criteria is viewModel.stateObservable.test().assertValue(...)
.
I would recommend mocking any dependencies that someAction
will delegate responsibility to and pretend it returns the expected result. This approach only have you mock adjacent classes.ursus
08/18/2020, 8:38 PMJohn Leeroy
08/18/2020, 8:45 PMursus
08/18/2020, 8:51 PMclass LoginViewModel(initialState: State, authManager: AuthManager, ...) {
init {
authManager.loginState
.subscribe {
when {
Loading -> setState { copy(logginIn = true) }
Success -> setState { copy(logginIn = false) }
}
}
}
fun loginClicked() {
authManager.login(..)
}
data class State(loggingIn: Boolean = false)
}
@Test fun test() {
val viewModel = createLoginViewModelWithAllTransitiveDependenciesLikeACrazyPerson()
val stateObserver = viewModel.state.test()
viewModel.loginClicked()
stateObserver.assertValues(State(logginIn = true), State(logginIn = false)
}
class FakeAuthApi {
fun login(): Single<Tokens> {
return Single.just(Tokens("fake-access-token", "fake-refresh-token"))
}
}
John Leeroy
08/18/2020, 8:54 PMursus
08/18/2020, 8:54 PMVertical slices of your app, testing interactions on a particular screen. Such a test verifies the interactions throughout the layers of your app's stack.same issue, do I use real impls and only fake out the edges?
John Leeroy
08/18/2020, 9:01 PMursus
08/18/2020, 9:01 PMJohn Leeroy
08/18/2020, 9:03 PMursus
08/18/2020, 9:04 PMJohn Leeroy
08/18/2020, 9:04 PMursus
08/18/2020, 9:05 PMJohn Leeroy
08/18/2020, 9:15 PMursus
08/18/2020, 9:18 PM@Test test1 {
val authManager = object: AuthManager {
override val logginIn: Observable<Boolean>
get() = Observable.just(false) <---
override fun loginUser(code: String) {
}
override fun refreshUser(refreshToken: String) {
}
override fun logoutUser() {
}
}
....
}
@Test test2 {
val authManager = object: AuthManager {
override val logginIn: Observable<Boolean>
get() = Observable.just(true) <---
override fun loginUser(code: String) {
}
override fun refreshUser(refreshToken: String) {
}
override fun logoutUser() {
}
}
....
}
gildor
08/19/2020, 2:17 AMall the methods, in all testsLooks like work for test fixtures, you create one implementation of this AuthManager which used for tests (so you could easily return any data from it and reuse it in all tests
ursus
08/19/2020, 3:11 AMgildor
08/19/2020, 3:12 AMclass FakeAuthManager(isLoggedIn: Boolean, initialUser: User? = ...) : AuthManager {
private val logginInSubject = BehaviorSubject.createDefault(isLoggedIn)
override val logginIn = logginInSubject.hide()
override fun loginUser(code: String) {
// do some valiudation if you want
logginInSubject.onNext(true)
}
override fun refreshUser(refreshToken: String) {
// you can add api to this fake to specify new user
}
override fun logoutUser() {
logginInSubject.onNext(false)
}
}
ursus
08/19/2020, 6:07 PMviewModel.state.test().assertValues(true, false)
assertEquals tokensDb.tokens, Tokens("abc123", "cba321")
assertEquals userDb.users, User(..)
is this cool in 1 test case? or is this 3 cases
John Leeroy
08/19/2020, 11:45 PM