Skip to content

Commit f621e48

Browse files
author
Peter Bryant
committed
✨ Initial implementation of test library
1 parent 81c18df commit f621e48

File tree

21 files changed

+496
-42
lines changed

21 files changed

+496
-42
lines changed

build.gradle

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
buildscript {
22
ext {
3-
kotlin_version = '1.5.21'
4-
compose_version = '1.0.2'
3+
kotlin_version = '1.5.31'
4+
compose_version = '1.0.4'
55

66
}
77
repositories {
@@ -12,8 +12,8 @@ buildscript {
1212
}
1313
}
1414
dependencies {
15-
classpath "com.android.tools.build:gradle:7.0.2"
16-
classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"
15+
classpath "com.android.tools.build:gradle:7.0.3"
16+
classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:1.5.31"
1717
classpath 'org.jlleitschuh.gradle:ktlint-gradle:10.2.0'
1818
classpath "org.jetbrains.dokka:dokka-gradle-plugin:1.5.30"
1919
classpath 'com.github.dcendents:android-maven-gradle-plugin:2.1'

compose/build.gradle

Lines changed: 4 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -18,11 +18,11 @@ afterEvaluate {
1818
}
1919

2020
android {
21-
compileSdk 30
21+
compileSdk 31
2222

2323
defaultConfig {
2424
minSdk 21
25-
targetSdk 30
25+
targetSdk 31
2626
versionCode 1
2727
versionName "1.0"
2828

@@ -72,19 +72,17 @@ ktlint {
7272
}
7373

7474
dependencies {
75-
implementation 'androidx.core:core-ktx:1.6.0'
75+
implementation 'androidx.core:core-ktx:1.7.0'
7676
implementation 'androidx.appcompat:appcompat:1.3.1'
7777
implementation 'com.google.android.material:material:1.4.0'
7878

7979
implementation "androidx.compose.ui:ui:$compose_version"
8080
api project(path: ':core')
8181

8282
testImplementation 'junit:junit:4.13.2'
83+
testImplementation 'androidx.test.ext:junit-ktx:1.1.3'
8384
testImplementation 'org.robolectric:robolectric:4.6.1'
8485

85-
androidTestImplementation 'androidx.test.ext:junit:1.1.3'
86-
androidTestImplementation 'androidx.test.espresso:espresso-core:3.4.0'
87-
8886
testImplementation "androidx.compose.material:material:$compose_version"
8987
testImplementation "androidx.compose.ui:ui-test-junit4:$compose_version"
9088
testImplementation 'io.mockk:mockk:1.12.0'
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1 +1,2 @@
11
instrumentedPackages=androidx.loader.content
2+
sdk=30

core/build.gradle

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,8 +24,8 @@ java {
2424
dependencies {
2525
implementation 'org.jetbrains.kotlinx:kotlinx-coroutines-core:1.5.2'
2626

27-
testImplementation "org.jetbrains.kotlin:kotlin-test:$kotlin_version"
2827
testImplementation 'org.jetbrains.kotlinx:kotlinx-coroutines-test:1.5.2'
28+
testImplementation "org.jetbrains.kotlin:kotlin-test:$kotlin_version"
2929
testImplementation 'app.cash.turbine:turbine:0.6.1'
3030
testImplementation 'io.mockk:mockk:1.12.0'
3131

core/src/test/java/com/ptrbrynt/kotlin_bloc/core/BlocTest.kt

Lines changed: 6 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -63,17 +63,13 @@ internal class BlocTest {
6363
val bloc = CounterBloc()
6464

6565
bloc.stateFlow.test {
66-
bloc.add(Increment)
67-
68-
assertEquals(1, awaitItem())
69-
70-
bloc.add(Increment)
71-
72-
assertEquals(2, awaitItem())
73-
74-
bloc.add(Decrement)
66+
listOf(Increment, Increment, Decrement).forEach {
67+
bloc.add(it)
68+
}
7569

76-
assertEquals(1, awaitItem())
70+
listOf(1, 2, 1).forEach {
71+
assertEquals(it, awaitItem())
72+
}
7773
}
7874
}
7975

sample/build.gradle

Lines changed: 21 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,11 @@ android {
4444
excludes += '/META-INF/{AL2.0,LGPL2.1}'
4545
}
4646
}
47+
testOptions {
48+
unitTests {
49+
includeAndroidResources = true
50+
}
51+
}
4752
}
4853

4954
ktlint {
@@ -52,18 +57,26 @@ ktlint {
5257

5358
dependencies {
5459

55-
implementation 'androidx.core:core-ktx:1.6.0'
60+
implementation 'androidx.core:core-ktx:1.7.0'
5661
implementation 'androidx.appcompat:appcompat:1.3.1'
5762
implementation 'com.google.android.material:material:1.4.0'
5863
implementation "androidx.compose.ui:ui:$compose_version"
5964
implementation "androidx.compose.material:material:$compose_version"
6065
implementation "androidx.compose.ui:ui-tooling-preview:$compose_version"
61-
implementation 'androidx.lifecycle:lifecycle-runtime-ktx:2.3.1'
62-
implementation 'androidx.activity:activity-compose:1.3.1'
66+
implementation 'androidx.lifecycle:lifecycle-runtime-ktx:2.4.0'
67+
implementation 'androidx.activity:activity-compose:1.4.0'
6368
implementation project(path: ':compose')
64-
testImplementation 'junit:junit:4.+'
65-
androidTestImplementation 'androidx.test.ext:junit:1.1.2'
66-
androidTestImplementation 'androidx.test.espresso:espresso-core:3.3.0'
67-
androidTestImplementation "androidx.compose.ui:ui-test-junit4:$compose_version"
68-
debugImplementation "androidx.compose.ui:ui-tooling:$compose_version"
69+
testImplementation project(path: ':test')
70+
testImplementation 'junit:junit:4.13.2'
71+
testImplementation 'androidx.test.ext:junit-ktx:1.1.3'
72+
testImplementation 'org.robolectric:robolectric:4.6.1'
73+
74+
testImplementation "androidx.compose.material:material:$compose_version"
75+
testImplementation "androidx.compose.ui:ui-test-junit4:$compose_version"
76+
testImplementation 'io.mockk:mockk:1.12.0'
77+
78+
debugImplementation "androidx.compose.ui:ui-test-manifest:$compose_version"
79+
80+
testImplementation "org.jetbrains.kotlin:kotlin-test:$kotlin_version"
81+
testImplementation 'org.jetbrains.kotlinx:kotlinx-coroutines-test:1.5.2'
6982
}

sample/src/main/java/com/ptrbrynt/kotlin_bloc/sample/MainActivity.kt

Lines changed: 7 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,6 @@ import androidx.compose.ui.Alignment
2121
import androidx.compose.ui.Modifier
2222
import androidx.compose.ui.tooling.preview.Preview
2323
import com.ptrbrynt.kotlin_bloc.compose.BlocComposer
24-
import com.ptrbrynt.kotlin_bloc.compose.BlocListener
2524
import com.ptrbrynt.kotlin_bloc.compose.BlocSelector
2625
import com.ptrbrynt.kotlin_bloc.compose.rememberSaveableBloc
2726
import com.ptrbrynt.kotlin_bloc.core.BlocBase
@@ -45,9 +44,9 @@ class MainActivity : ComponentActivity() {
4544
* Creates a Counter based on [CounterBloc]
4645
*/
4746
@Composable
48-
fun BlocCounter() {
49-
val bloc = rememberSaveableBloc(initialState = 0) { CounterBloc(it) }
50-
47+
fun BlocCounter(
48+
bloc: CounterBloc = rememberSaveableBloc(initialState = 0) { CounterBloc(it) },
49+
) {
5150
CounterBase(
5251
bloc,
5352
onIncrement = {
@@ -60,9 +59,9 @@ fun BlocCounter() {
6059
* Creates a Counter based on [CounterCubit]
6160
*/
6261
@Composable
63-
64-
fun CubitCounter() {
65-
val cubit = remember { CounterCubit() }
62+
fun CubitCounter(
63+
cubit: CounterCubit = remember { CounterCubit() },
64+
) {
6665
CounterBase(
6766
cubit,
6867
onIncrement = { cubit.increment() }
@@ -75,9 +74,6 @@ fun CounterBase(
7574
onIncrement: () -> Unit,
7675
scaffoldState: ScaffoldState = rememberScaffoldState(),
7776
) {
78-
BlocListener(bloc) {
79-
scaffoldState.snackbarHostState.showSnackbar("$it")
80-
}
8177

8278
Scaffold(
8379
scaffoldState = scaffoldState,
@@ -106,9 +102,8 @@ fun CounterBase(
106102
@Composable
107103
fun BlocSelectorCounter(
108104
scaffoldState: ScaffoldState = rememberScaffoldState(),
105+
bloc: CounterBloc = rememberSaveableBloc(initialState = 0) { CounterBloc(it) },
109106
) {
110-
val bloc = rememberSaveableBloc(initialState = 0) { CounterBloc(it) }
111-
112107
Scaffold(
113108
scaffoldState = scaffoldState,
114109
floatingActionButton = {

sample/src/main/java/com/ptrbrynt/kotlin_bloc/sample/ui/cubits/CounterCubit.kt

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,5 +4,7 @@ import com.ptrbrynt.kotlin_bloc.core.Cubit
44
import kotlinx.coroutines.launch
55

66
class CounterCubit : Cubit<Int>(0) {
7-
fun increment() = blocScope.launch { emit(state + 1) }
7+
fun increment() {
8+
blocScope.launch { emit(state + 1) }
9+
}
810
}
Lines changed: 141 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,141 @@
1+
package com.ptrbrynt.kotlin_bloc.sample
2+
3+
import androidx.compose.material.MaterialTheme
4+
import androidx.compose.ui.test.assertIsDisplayed
5+
import androidx.compose.ui.test.junit4.createComposeRule
6+
import androidx.compose.ui.test.onNodeWithContentDescription
7+
import androidx.compose.ui.test.onNodeWithText
8+
import androidx.compose.ui.test.performClick
9+
import androidx.test.ext.junit.runners.AndroidJUnit4
10+
import com.ptrbrynt.kotlin_bloc.sample.ui.blocs.CounterBloc
11+
import com.ptrbrynt.kotlin_bloc.sample.ui.blocs.CounterEvent
12+
import com.ptrbrynt.kotlin_bloc.sample.ui.cubits.CounterCubit
13+
import com.ptrbrynt.kotlin_bloc.test.mockBloc
14+
import com.ptrbrynt.kotlin_bloc.test.mockCubit
15+
import com.ptrbrynt.kotlin_bloc.test.whenListen
16+
import io.mockk.verify
17+
import kotlinx.coroutines.flow.MutableStateFlow
18+
import kotlinx.coroutines.flow.emptyFlow
19+
import org.junit.Rule
20+
import org.junit.Test
21+
import org.junit.runner.RunWith
22+
23+
@RunWith(AndroidJUnit4::class)
24+
class MainActivityTest {
25+
@get:Rule
26+
val composableTestRule = createComposeRule()
27+
28+
@Test
29+
fun blocCounterDisplaysBlocState() {
30+
val bloc = mockBloc<CounterBloc, CounterEvent, Int>()
31+
32+
val flow = MutableStateFlow(1)
33+
34+
whenListen(bloc, flow, initialState = flow.value)
35+
36+
composableTestRule.setContent {
37+
MaterialTheme {
38+
BlocCounter(bloc = bloc)
39+
}
40+
}
41+
42+
composableTestRule.onNodeWithText("1").assertIsDisplayed()
43+
44+
flow.tryEmit(2)
45+
46+
composableTestRule.onNodeWithText("2").assertIsDisplayed()
47+
}
48+
49+
@Test
50+
fun blocCounterIncrementButtonAddsIncrement() {
51+
val bloc = mockBloc<CounterBloc, CounterEvent, Int>()
52+
53+
whenListen(bloc, emptyFlow(), initialState = 1)
54+
55+
composableTestRule.setContent {
56+
MaterialTheme {
57+
BlocCounter(bloc = bloc)
58+
}
59+
}
60+
61+
composableTestRule.onNodeWithContentDescription("Add").performClick()
62+
63+
verify { bloc.add(CounterEvent.Increment) }
64+
}
65+
66+
@Test
67+
fun cubitCounterDisplaysBlocState() {
68+
val cubit = mockCubit<CounterCubit, Int>()
69+
70+
val flow = MutableStateFlow(1)
71+
72+
whenListen(cubit, flow, initialState = flow.value)
73+
74+
composableTestRule.setContent {
75+
MaterialTheme {
76+
CubitCounter(cubit = cubit)
77+
}
78+
}
79+
80+
composableTestRule.onNodeWithText("1").assertIsDisplayed()
81+
82+
flow.tryEmit(2)
83+
84+
composableTestRule.onNodeWithText("2").assertIsDisplayed()
85+
}
86+
87+
@Test
88+
fun cubitCounterIncrementButtonCallsIncrement() {
89+
val cubit = mockCubit<CounterCubit, Int>()
90+
91+
whenListen(cubit, emptyFlow(), initialState = 1)
92+
93+
composableTestRule.setContent {
94+
MaterialTheme {
95+
CubitCounter(cubit = cubit)
96+
}
97+
}
98+
99+
composableTestRule.onNodeWithContentDescription("Add").performClick()
100+
101+
verify { cubit.increment() }
102+
}
103+
104+
@Test
105+
fun blocSelectorCounterDisplaysBlocState() {
106+
val bloc = mockBloc<CounterBloc, CounterEvent, Int>()
107+
108+
val flow = MutableStateFlow(1)
109+
110+
whenListen(bloc, flow, initialState = flow.value)
111+
112+
composableTestRule.setContent {
113+
MaterialTheme {
114+
BlocSelectorCounter(bloc = bloc)
115+
}
116+
}
117+
118+
composableTestRule.onNodeWithText("The counter is 1").assertIsDisplayed()
119+
120+
flow.tryEmit(2)
121+
122+
composableTestRule.onNodeWithText("The counter is 2").assertIsDisplayed()
123+
}
124+
125+
@Test
126+
fun blocSelectorCounterIncrementButtonAddsIncrement() {
127+
val bloc = mockBloc<CounterBloc, CounterEvent, Int>()
128+
129+
whenListen(bloc, emptyFlow(), initialState = 1)
130+
131+
composableTestRule.setContent {
132+
MaterialTheme {
133+
BlocSelectorCounter(bloc = bloc)
134+
}
135+
}
136+
137+
composableTestRule.onNodeWithContentDescription("Add").performClick()
138+
139+
verify { bloc.add(CounterEvent.Increment) }
140+
}
141+
}
Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
package com.ptrbrynt.kotlin_bloc.sample.ui.blocs
2+
3+
import com.ptrbrynt.kotlin_bloc.test.testBloc
4+
import kotlin.time.ExperimentalTime
5+
import kotlinx.coroutines.runBlocking
6+
import org.junit.Test
7+
8+
@ExperimentalTime
9+
class CounterBlocTest {
10+
@Test
11+
fun counterBlocTest() = runBlocking {
12+
testBloc(
13+
build = { CounterBloc(0) },
14+
act = {
15+
add(CounterEvent.Increment)
16+
add(CounterEvent.Increment)
17+
add(CounterEvent.Decrement)
18+
},
19+
expected = listOf(
20+
{ equals(1) },
21+
{ equals(2) },
22+
{ equals(1) },
23+
)
24+
)
25+
}
26+
}

0 commit comments

Comments
 (0)