Skip to content

Commit 6d1f85b

Browse files
authored
Merge pull request #607 from android/mv/tests
Provide a CoroutineScope to fake DataStores
2 parents 0844d02 + 755413b commit 6d1f85b

File tree

6 files changed

+79
-46
lines changed

6 files changed

+79
-46
lines changed

core/data/src/test/java/com/google/samples/apps/nowinandroid/core/data/repository/OfflineFirstNewsRepositoryTest.kt

Lines changed: 12 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,8 @@ import com.google.samples.apps.nowinandroid.core.model.data.NewsResource
3636
import com.google.samples.apps.nowinandroid.core.network.model.NetworkChangeList
3737
import com.google.samples.apps.nowinandroid.core.network.model.NetworkNewsResource
3838
import kotlinx.coroutines.flow.first
39+
import kotlinx.coroutines.test.TestScope
40+
import kotlinx.coroutines.test.UnconfinedTestDispatcher
3941
import kotlinx.coroutines.test.runTest
4042
import org.junit.Before
4143
import org.junit.Rule
@@ -45,6 +47,8 @@ import kotlin.test.assertEquals
4547

4648
class OfflineFirstNewsRepositoryTest {
4749

50+
private val testScope = TestScope(UnconfinedTestDispatcher())
51+
4852
private lateinit var subject: OfflineFirstNewsRepository
4953

5054
private lateinit var newsResourceDao: TestNewsResourceDao
@@ -65,7 +69,7 @@ class OfflineFirstNewsRepositoryTest {
6569
network = TestNiaNetworkDataSource()
6670
synchronizer = TestSynchronizer(
6771
NiaPreferencesDataSource(
68-
tmpFolder.testUserPreferencesDataStore(),
72+
tmpFolder.testUserPreferencesDataStore(testScope),
6973
),
7074
)
7175

@@ -78,7 +82,7 @@ class OfflineFirstNewsRepositoryTest {
7882

7983
@Test
8084
fun offlineFirstNewsRepository_news_resources_stream_is_backed_by_news_resource_dao() =
81-
runTest {
85+
testScope.runTest {
8286
assertEquals(
8387
newsResourceDao.getNewsResources()
8488
.first()
@@ -90,7 +94,7 @@ class OfflineFirstNewsRepositoryTest {
9094

9195
@Test
9296
fun offlineFirstNewsRepository_news_resources_for_topic_is_backed_by_news_resource_dao() =
93-
runTest {
97+
testScope.runTest {
9498
assertEquals(
9599
expected = newsResourceDao.getNewsResources(
96100
filterTopicIds = filteredInterestsIds,
@@ -119,7 +123,7 @@ class OfflineFirstNewsRepositoryTest {
119123

120124
@Test
121125
fun offlineFirstNewsRepository_sync_pulls_from_network() =
122-
runTest {
126+
testScope.runTest {
123127
subject.syncWith(synchronizer)
124128

125129
val newsResourcesFromNetwork = network.getNewsResources()
@@ -144,7 +148,7 @@ class OfflineFirstNewsRepositoryTest {
144148

145149
@Test
146150
fun offlineFirstNewsRepository_sync_deletes_items_marked_deleted_on_network() =
147-
runTest {
151+
testScope.runTest {
148152
val newsResourcesFromNetwork = network.getNewsResources()
149153
.map(NetworkNewsResource::asEntity)
150154
.map(NewsResourceEntity::asExternalModel)
@@ -185,7 +189,7 @@ class OfflineFirstNewsRepositoryTest {
185189

186190
@Test
187191
fun offlineFirstNewsRepository_incremental_sync_pulls_from_network() =
188-
runTest {
192+
testScope.runTest {
189193
// Set news version to 7
190194
synchronizer.updateChangeListVersions {
191195
copy(newsResourceVersion = 7)
@@ -224,7 +228,7 @@ class OfflineFirstNewsRepositoryTest {
224228

225229
@Test
226230
fun offlineFirstNewsRepository_sync_saves_shell_topic_entities() =
227-
runTest {
231+
testScope.runTest {
228232
subject.syncWith(synchronizer)
229233

230234
assertEquals(
@@ -239,7 +243,7 @@ class OfflineFirstNewsRepositoryTest {
239243

240244
@Test
241245
fun offlineFirstNewsRepository_sync_saves_topic_cross_references() =
242-
runTest {
246+
testScope.runTest {
243247
subject.syncWith(synchronizer)
244248

245249
assertEquals(

core/data/src/test/java/com/google/samples/apps/nowinandroid/core/data/repository/OfflineFirstTopicsRepositoryTest.kt

Lines changed: 9 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,8 @@ import com.google.samples.apps.nowinandroid.core.datastore.test.testUserPreferen
2929
import com.google.samples.apps.nowinandroid.core.model.data.Topic
3030
import com.google.samples.apps.nowinandroid.core.network.model.NetworkTopic
3131
import kotlinx.coroutines.flow.first
32+
import kotlinx.coroutines.test.TestScope
33+
import kotlinx.coroutines.test.UnconfinedTestDispatcher
3234
import kotlinx.coroutines.test.runTest
3335
import org.junit.Before
3436
import org.junit.Rule
@@ -38,6 +40,8 @@ import kotlin.test.assertEquals
3840

3941
class OfflineFirstTopicsRepositoryTest {
4042

43+
private val testScope = TestScope(UnconfinedTestDispatcher())
44+
4145
private lateinit var subject: OfflineFirstTopicsRepository
4246

4347
private lateinit var topicDao: TopicDao
@@ -56,7 +60,7 @@ class OfflineFirstTopicsRepositoryTest {
5660
topicDao = TestTopicDao()
5761
network = TestNiaNetworkDataSource()
5862
niaPreferences = NiaPreferencesDataSource(
59-
tmpFolder.testUserPreferencesDataStore(),
63+
tmpFolder.testUserPreferencesDataStore(testScope),
6064
)
6165
synchronizer = TestSynchronizer(niaPreferences)
6266

@@ -68,7 +72,7 @@ class OfflineFirstTopicsRepositoryTest {
6872

6973
@Test
7074
fun offlineFirstTopicsRepository_topics_stream_is_backed_by_topics_dao() =
71-
runTest {
75+
testScope.runTest {
7276
assertEquals(
7377
topicDao.getTopicEntities()
7478
.first()
@@ -80,7 +84,7 @@ class OfflineFirstTopicsRepositoryTest {
8084

8185
@Test
8286
fun offlineFirstTopicsRepository_sync_pulls_from_network() =
83-
runTest {
87+
testScope.runTest {
8488
subject.syncWith(synchronizer)
8589

8690
val networkTopics = network.getTopics()
@@ -103,7 +107,7 @@ class OfflineFirstTopicsRepositoryTest {
103107

104108
@Test
105109
fun offlineFirstTopicsRepository_incremental_sync_pulls_from_network() =
106-
runTest {
110+
testScope.runTest {
107111
// Set topics version to 10
108112
synchronizer.updateChangeListVersions {
109113
copy(topicVersion = 10)
@@ -133,7 +137,7 @@ class OfflineFirstTopicsRepositoryTest {
133137

134138
@Test
135139
fun offlineFirstTopicsRepository_sync_deletes_items_marked_deleted_on_network() =
136-
runTest {
140+
testScope.runTest {
137141
val networkTopics = network.getTopics()
138142
.map(NetworkTopic::asEntity)
139143
.map(TopicEntity::asExternalModel)

core/data/src/test/java/com/google/samples/apps/nowinandroid/core/data/repository/OfflineFirstUserDataRepositoryTest.kt

Lines changed: 14 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,8 @@ import com.google.samples.apps.nowinandroid.core.model.data.ThemeBrand
2424
import com.google.samples.apps.nowinandroid.core.model.data.UserData
2525
import kotlinx.coroutines.flow.first
2626
import kotlinx.coroutines.flow.map
27+
import kotlinx.coroutines.test.TestScope
28+
import kotlinx.coroutines.test.UnconfinedTestDispatcher
2729
import kotlinx.coroutines.test.runTest
2830
import org.junit.Before
2931
import org.junit.Rule
@@ -34,6 +36,9 @@ import kotlin.test.assertFalse
3436
import kotlin.test.assertTrue
3537

3638
class OfflineFirstUserDataRepositoryTest {
39+
40+
private val testScope = TestScope(UnconfinedTestDispatcher())
41+
3742
private lateinit var subject: OfflineFirstUserDataRepository
3843

3944
private lateinit var niaPreferencesDataSource: NiaPreferencesDataSource
@@ -46,7 +51,7 @@ class OfflineFirstUserDataRepositoryTest {
4651
@Before
4752
fun setup() {
4853
niaPreferencesDataSource = NiaPreferencesDataSource(
49-
tmpFolder.testUserPreferencesDataStore(),
54+
tmpFolder.testUserPreferencesDataStore(testScope),
5055
)
5156

5257
subject = OfflineFirstUserDataRepository(
@@ -57,7 +62,7 @@ class OfflineFirstUserDataRepositoryTest {
5762

5863
@Test
5964
fun offlineFirstUserDataRepository_default_user_data_is_correct() =
60-
runTest {
65+
testScope.runTest {
6166
assertEquals(
6267
UserData(
6368
bookmarkedNewsResources = emptySet(),
@@ -73,7 +78,7 @@ class OfflineFirstUserDataRepositoryTest {
7378

7479
@Test
7580
fun offlineFirstUserDataRepository_toggle_followed_topics_logic_delegates_to_nia_preferences() =
76-
runTest {
81+
testScope.runTest {
7782
subject.toggleFollowedTopicId(followedTopicId = "0", followed = true)
7883

7984
assertEquals(
@@ -104,7 +109,7 @@ class OfflineFirstUserDataRepositoryTest {
104109

105110
@Test
106111
fun offlineFirstUserDataRepository_set_followed_topics_logic_delegates_to_nia_preferences() =
107-
runTest {
112+
testScope.runTest {
108113
subject.setFollowedTopicIds(followedTopicIds = setOf("1", "2"))
109114

110115
assertEquals(
@@ -126,7 +131,7 @@ class OfflineFirstUserDataRepositoryTest {
126131

127132
@Test
128133
fun offlineFirstUserDataRepository_bookmark_news_resource_logic_delegates_to_nia_preferences() =
129-
runTest {
134+
testScope.runTest {
130135
subject.updateNewsResourceBookmark(newsResourceId = "0", bookmarked = true)
131136

132137
assertEquals(
@@ -157,7 +162,7 @@ class OfflineFirstUserDataRepositoryTest {
157162

158163
@Test
159164
fun offlineFirstUserDataRepository_set_theme_brand_delegates_to_nia_preferences() =
160-
runTest {
165+
testScope.runTest {
161166
subject.setThemeBrand(ThemeBrand.ANDROID)
162167

163168
assertEquals(
@@ -177,7 +182,7 @@ class OfflineFirstUserDataRepositoryTest {
177182

178183
@Test
179184
fun offlineFirstUserDataRepository_set_dynamic_color_delegates_to_nia_preferences() =
180-
runTest {
185+
testScope.runTest {
181186
subject.setDynamicColorPreference(true)
182187

183188
assertEquals(
@@ -197,7 +202,7 @@ class OfflineFirstUserDataRepositoryTest {
197202

198203
@Test
199204
fun offlineFirstUserDataRepository_set_dark_theme_config_delegates_to_nia_preferences() =
200-
runTest {
205+
testScope.runTest {
201206
subject.setDarkThemeConfig(DarkThemeConfig.DARK)
202207

203208
assertEquals(
@@ -217,7 +222,7 @@ class OfflineFirstUserDataRepositoryTest {
217222

218223
@Test
219224
fun whenUserCompletesOnboarding_thenRemovesAllInterests_shouldHideOnboardingIsFalse() =
220-
runTest {
225+
testScope.runTest {
221226
subject.setFollowedTopicIds(setOf("1"))
222227
subject.setShouldHideOnboarding(true)
223228
assertTrue(subject.userData.first().shouldHideOnboarding)

core/datastore-test/build.gradle.kts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@ android {
2424

2525
dependencies {
2626
api(project(":core:datastore"))
27+
implementation(project(":core:common"))
2728
implementation(project(":core:testing"))
2829

2930
api(libs.androidx.dataStore.core)

core/datastore-test/src/main/java/com/google/samples/apps/nowinandroid/core/datastore/test/TestDataStoreModule.kt

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,10 +21,15 @@ import androidx.datastore.core.DataStoreFactory
2121
import com.google.samples.apps.nowinandroid.core.datastore.UserPreferences
2222
import com.google.samples.apps.nowinandroid.core.datastore.UserPreferencesSerializer
2323
import com.google.samples.apps.nowinandroid.core.datastore.di.DataStoreModule
24+
import com.google.samples.apps.nowinandroid.core.network.Dispatcher
25+
import com.google.samples.apps.nowinandroid.core.network.NiaDispatchers.IO
2426
import dagger.Module
2527
import dagger.Provides
2628
import dagger.hilt.components.SingletonComponent
2729
import dagger.hilt.testing.TestInstallIn
30+
import kotlinx.coroutines.CoroutineDispatcher
31+
import kotlinx.coroutines.CoroutineScope
32+
import kotlinx.coroutines.SupervisorJob
2833
import org.junit.rules.TemporaryFolder
2934
import javax.inject.Singleton
3035

@@ -38,16 +43,23 @@ object TestDataStoreModule {
3843
@Provides
3944
@Singleton
4045
fun providesUserPreferencesDataStore(
46+
@Dispatcher(IO) ioDispatcher: CoroutineDispatcher,
4147
userPreferencesSerializer: UserPreferencesSerializer,
4248
tmpFolder: TemporaryFolder,
4349
): DataStore<UserPreferences> =
44-
tmpFolder.testUserPreferencesDataStore(userPreferencesSerializer)
50+
tmpFolder.testUserPreferencesDataStore(
51+
// TODO: Provide an application-wide CoroutineScope in the DI graph
52+
coroutineScope = CoroutineScope(SupervisorJob() + ioDispatcher),
53+
userPreferencesSerializer = userPreferencesSerializer,
54+
)
4555
}
4656

4757
fun TemporaryFolder.testUserPreferencesDataStore(
58+
coroutineScope: CoroutineScope,
4859
userPreferencesSerializer: UserPreferencesSerializer = UserPreferencesSerializer(),
4960
) = DataStoreFactory.create(
5061
serializer = userPreferencesSerializer,
62+
scope = coroutineScope,
5163
) {
5264
newFile("user_preferences_test.pb")
5365
}

0 commit comments

Comments
 (0)