Getting the following error,
Only a single call to
runTest
can be performed during one test.
In-unit tests for data store.
The issue is clearly because I have runTest
in @After
for data store cleanup after each test.
How do I fix this issue?
Migrating from runBlockingTest
to runTest
Code
@HiltAndroidTest
@OptIn(ExperimentalCoroutinesApi::class)
@RunWith(AndroidJUnit4::class)
class MyPreferencesDataSourceTest {
private val testContext: Context = ApplicationProvider.getApplicationContext()
private val testDispatcher = UnconfinedTestDispatcher()
private val testScope = TestScope(testDispatcher + Job())
@get:Rule(order = 0)
var hiltRule = HiltAndroidRule(this)
@get:Rule(order = 1)
val mainDispatcherRule = MainDispatcherRule()
private val testDataStore: DataStore<Preferences> = PreferenceDataStoreFactory.create(
scope = testScope,
produceFile = {
testContext.preferencesDataStoreFile(
name = AppConstants.APP_NAME,
)
},
)
private lateinit var appPreferenceDataSource: AppPreferenceDataSource
@Before
fun setUp() {
hiltRule.inject()
appPreferenceDataSource = AppPreferenceDataSource(
dataStore = testDataStore,
)
}
@After
fun tearDown() = testScope.runTest {
testDataStore.edit {
it.clear()
}
testScope.cancel()
}
@Test
fun getCurrencyBase_returnsNull() = testScope.runTest {
val result = appPreferenceDataSource.getData().first()
Assert.assertNull(result)
}
}
Though this is not exactly what I was looking for, this is the best solution I could find so far.
I am open to better ways if there are any.
Source - Kotlinlang Slack
With a little modification from the Slack message, I created this helper function.
private fun runTestAndCleanup(
block: suspend () -> Unit,
) = testScope.runTest {
block()
testDataStore.edit {
it.clear()
}
}
And I replaced all the usages of testScope.runTest
with runTestAndCleanup
.