Skip to content

Commit b2c0319

Browse files
committed
test(AddVM) setup
1 parent 4d2389c commit b2c0319

File tree

7 files changed

+147
-18
lines changed

7 files changed

+147
-18
lines changed

feature-add/build.gradle.kts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -62,4 +62,5 @@ dependencies {
6262
implementation(deps.timber)
6363

6464
addUnitTest()
65+
testImplementation(mviTesting)
6566
}

feature-add/src/main/java/com/hoc/flowmvi/ui/add/AddContract.kt

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -62,7 +62,8 @@ internal sealed interface PartialStateChange {
6262
fun reduce(viewState: ViewState): ViewState
6363

6464
data class ErrorsChanged(val errors: Set<ValidationError>) : PartialStateChange {
65-
override fun reduce(viewState: ViewState) = viewState.copy(errors = errors)
65+
override fun reduce(viewState: ViewState) =
66+
if (viewState.errors == errors) viewState else viewState.copy(errors = errors)
6667
}
6768

6869
sealed class AddUser : PartialStateChange {

feature-add/src/main/java/com/hoc/flowmvi/ui/add/AddVM.kt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -168,10 +168,10 @@ class AddVM(
168168
}
169169

170170
return merge(
171+
formValuesChanges,
171172
errorsChanges,
172173
addUserChanges,
173174
firstChanges,
174-
formValuesChanges,
175175
)
176176
}
177177

Lines changed: 137 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,137 @@
1+
package com.hoc.flowmvi.ui.add
2+
3+
import androidx.lifecycle.SavedStateHandle
4+
import com.flowmvi.mvi_testing.BaseMviViewModelTest
5+
import com.flowmvi.mvi_testing.mapRight
6+
import com.hoc.flowmvi.domain.usecase.AddUserUseCase
7+
import io.mockk.confirmVerified
8+
import io.mockk.mockk
9+
import kotlinx.coroutines.ExperimentalCoroutinesApi
10+
import kotlinx.coroutines.flow.flowOf
11+
import kotlin.test.Test
12+
import kotlin.time.ExperimentalTime
13+
14+
private val ALL_ERRORS = ValidationError.values().toSet()
15+
16+
@ExperimentalCoroutinesApi
17+
@ExperimentalTime
18+
class AddVMTest : BaseMviViewModelTest<ViewIntent, ViewState, SingleEvent, AddVM>() {
19+
private lateinit var vm: AddVM
20+
private lateinit var addUser: AddUserUseCase
21+
private lateinit var savedStateHandle: SavedStateHandle
22+
23+
override fun setup() {
24+
super.setup()
25+
26+
addUser = mockk()
27+
savedStateHandle = SavedStateHandle()
28+
29+
vm = AddVM(
30+
addUser = addUser,
31+
savedStateHandle = savedStateHandle
32+
)
33+
}
34+
35+
override fun tearDown() {
36+
confirmVerified(
37+
addUser,
38+
)
39+
40+
super.tearDown()
41+
}
42+
43+
@Test
44+
fun test_withFormValueIntents_returnsStateWithChangedValuesWithErrors() {
45+
test(
46+
vmProducer = { vm },
47+
intents = flowOf(
48+
ViewIntent.EmailChanged(""),
49+
ViewIntent.FirstNameChanged(""),
50+
ViewIntent.LastNameChanged(""),
51+
// all fields changed
52+
ViewIntent.EmailChanged("a"),
53+
ViewIntent.FirstNameChanged("b"),
54+
ViewIntent.LastNameChanged("c"),
55+
),
56+
expectedStates = listOf(
57+
ViewState.initial(
58+
email = null,
59+
firstName = null,
60+
lastName = null,
61+
),
62+
ViewState(
63+
errors = emptySet(),
64+
isLoading = false,
65+
emailChanged = false,
66+
firstNameChanged = false,
67+
lastNameChanged = false,
68+
email = "",
69+
firstName = null,
70+
lastName = null
71+
),
72+
ViewState(
73+
errors = emptySet(),
74+
isLoading = false,
75+
emailChanged = false,
76+
firstNameChanged = false,
77+
lastNameChanged = false,
78+
email = "",
79+
firstName = "",
80+
lastName = null
81+
),
82+
ViewState(
83+
errors = emptySet(),
84+
isLoading = false,
85+
emailChanged = false,
86+
firstNameChanged = false,
87+
lastNameChanged = false,
88+
email = "",
89+
firstName = "",
90+
lastName = ""
91+
),
92+
ViewState(
93+
errors = ALL_ERRORS,
94+
isLoading = false,
95+
emailChanged = false,
96+
firstNameChanged = false,
97+
lastNameChanged = false,
98+
email = "",
99+
firstName = "",
100+
lastName = ""
101+
),
102+
// all fields changed.
103+
ViewState(
104+
errors = ALL_ERRORS,
105+
isLoading = false,
106+
emailChanged = false,
107+
firstNameChanged = false,
108+
lastNameChanged = false,
109+
email = "a",
110+
firstName = "",
111+
lastName = ""
112+
),
113+
ViewState(
114+
errors = ALL_ERRORS,
115+
isLoading = false,
116+
emailChanged = false,
117+
firstNameChanged = false,
118+
lastNameChanged = false,
119+
email = "a",
120+
firstName = "b",
121+
lastName = ""
122+
),
123+
ViewState(
124+
errors = ALL_ERRORS,
125+
isLoading = false,
126+
emailChanged = false,
127+
firstNameChanged = false,
128+
lastNameChanged = false,
129+
email = "a",
130+
firstName = "b",
131+
lastName = "c"
132+
)
133+
).mapRight(),
134+
expectedEvents = listOf(),
135+
)
136+
}
137+
}

feature-add/src/test/java/com/hoc/flowmvi/ui/add/ExampleUnitTest.kt

Lines changed: 0 additions & 11 deletions
This file was deleted.

mvi/mvi-testing/build.gradle.kts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -52,7 +52,7 @@ dependencies {
5252
implementation(deps.coroutines.core)
5353

5454
implementation(mviBase)
55-
implementation(testUtils)
55+
api(testUtils)
5656
implementation(deps.timber)
5757

5858
implementation(deps.arrow.core)

mvi/mvi-testing/src/main/java/com/flowmvi/mvi_testing/BaseMviViewModelTest.kt

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ import kotlinx.coroutines.delay
1515
import kotlinx.coroutines.flow.Flow
1616
import kotlinx.coroutines.flow.collect
1717
import kotlinx.coroutines.flow.onCompletion
18+
import kotlinx.coroutines.flow.onEach
1819
import kotlinx.coroutines.flow.toList
1920
import kotlinx.coroutines.launch
2021
import kotlinx.coroutines.test.runBlockingTest
@@ -63,7 +64,7 @@ abstract class BaseMviViewModelTest<
6364

6465
val vm = vmProducer()
6566
intentsBeforeCollecting
66-
?.onCompletion { logIfEnabled { "---------------" } }
67+
?.onCompletion { logIfEnabled { "-".repeat(32) } }
6768
?.collect {
6869
vm.processIntent(it)
6970
logIfEnabled { "[BEFORE] Dispatch $it -> $vm" }
@@ -74,15 +75,15 @@ abstract class BaseMviViewModelTest<
7475
val states = mutableListOf<S>()
7576
val events = mutableListOf<E>()
7677

77-
val stateJob = launch(start = CoroutineStart.UNDISPATCHED) { vm.viewState.toList(states) }
78+
val stateJob = launch(start = CoroutineStart.UNDISPATCHED) { vm.viewState.onEach { logIfEnabled { "[STATE] <- $it" } }.toList(states) }
7879
val eventJob = launch(start = CoroutineStart.UNDISPATCHED) { vm.singleEvent.toList(events) }
7980

8081
intents.collect {
81-
vm.processIntent(it)
8282
logIfEnabled { "[DISPATCH] Dispatch $it -> $vm" }
83+
vm.processIntent(it)
8384
}
8485
delay(delayAfterDispatchingIntents)
85-
logIfEnabled { "---------------" }
86+
logIfEnabled { "-".repeat(32) }
8687

8788
logIfEnabled { "[DONE] states=${states.joinToStringWithIndex()}" }
8889
logIfEnabled { "[DONE] events=${events.joinToStringWithIndex()}" }

0 commit comments

Comments
 (0)