Add Hilt(Dagger) example of robolectric tests in app
This commit is contained in:
parent
7a0776ba9d
commit
e8d0c746b9
6 changed files with 132 additions and 34 deletions
|
|
@ -51,6 +51,13 @@ android {
|
||||||
java.srcDirs += "src/sharedTest/java"
|
java.srcDirs += "src/sharedTest/java"
|
||||||
java.srcDirs += "src/robolectricTest/java"
|
java.srcDirs += "src/robolectricTest/java"
|
||||||
}
|
}
|
||||||
|
testHilt {
|
||||||
|
java.srcDirs += "src/robolectricTestHilt/java"
|
||||||
|
resources.srcDirs += "src/robolectricTestHilt/resources"
|
||||||
|
}
|
||||||
|
testKoin {
|
||||||
|
java.srcDirs += "src/robolectricTestKoin/java"
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// needed for androidTest
|
// needed for androidTest
|
||||||
|
|
@ -89,9 +96,7 @@ dependencies {
|
||||||
koinImplementation "io.insert-koin:koin-android:$koin_version"
|
koinImplementation "io.insert-koin:koin-android:$koin_version"
|
||||||
|
|
||||||
// Hilt
|
// Hilt
|
||||||
// hiltImplementation "com.google.dagger:hilt-android:$hilt_version"
|
|
||||||
implementation "com.google.dagger:hilt-android:$hilt_version"
|
implementation "com.google.dagger:hilt-android:$hilt_version"
|
||||||
// implementation "com.google.dagger:hilt-core:$hilt_version"
|
|
||||||
kaptHilt "com.google.dagger:hilt-compiler:$hilt_version"
|
kaptHilt "com.google.dagger:hilt-compiler:$hilt_version"
|
||||||
hiltImplementation "androidx.activity:activity-ktx:$activity_ktx_version"
|
hiltImplementation "androidx.activity:activity-ktx:$activity_ktx_version"
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,97 @@
|
||||||
|
package org.fnives.test.showcase.favourite
|
||||||
|
|
||||||
|
import androidx.test.ext.junit.runners.AndroidJUnit4
|
||||||
|
import dagger.hilt.android.testing.HiltAndroidRule
|
||||||
|
import dagger.hilt.android.testing.HiltAndroidTest
|
||||||
|
import kotlinx.coroutines.ExperimentalCoroutinesApi
|
||||||
|
import kotlinx.coroutines.async
|
||||||
|
import kotlinx.coroutines.flow.first
|
||||||
|
import kotlinx.coroutines.flow.take
|
||||||
|
import kotlinx.coroutines.flow.toList
|
||||||
|
import kotlinx.coroutines.runBlocking
|
||||||
|
import kotlinx.coroutines.test.TestCoroutineDispatcher
|
||||||
|
import org.fnives.test.showcase.core.storage.content.FavouriteContentLocalStorage
|
||||||
|
import org.fnives.test.showcase.model.content.ContentId
|
||||||
|
import org.fnives.test.showcase.storage.database.DatabaseInitialization
|
||||||
|
import org.junit.Assert
|
||||||
|
import org.junit.Before
|
||||||
|
import org.junit.Rule
|
||||||
|
import org.junit.Test
|
||||||
|
import org.junit.runner.RunWith
|
||||||
|
import javax.inject.Inject
|
||||||
|
|
||||||
|
@Suppress("TestFunctionName")
|
||||||
|
@OptIn(ExperimentalCoroutinesApi::class)
|
||||||
|
@RunWith(AndroidJUnit4::class)
|
||||||
|
@HiltAndroidTest
|
||||||
|
internal class FavouriteContentLocalStorageImplTest {
|
||||||
|
|
||||||
|
@get:Rule
|
||||||
|
val hiltRule = HiltAndroidRule(this)
|
||||||
|
|
||||||
|
@Inject
|
||||||
|
lateinit var sut : FavouriteContentLocalStorage
|
||||||
|
private lateinit var testDispatcher: TestCoroutineDispatcher
|
||||||
|
|
||||||
|
@Before
|
||||||
|
fun setUp() {
|
||||||
|
testDispatcher = TestCoroutineDispatcher()
|
||||||
|
DatabaseInitialization.dispatcher = testDispatcher
|
||||||
|
hiltRule.inject()
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun GIVEN_content_id_WHEN_added_to_Favourite_THEN_it_can_be_read_out() = runBlocking {
|
||||||
|
val expected = listOf(ContentId("a"))
|
||||||
|
|
||||||
|
sut.markAsFavourite(ContentId("a"))
|
||||||
|
val actual = sut.observeFavourites().first()
|
||||||
|
|
||||||
|
Assert.assertEquals(expected, actual)
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun GIVEN_content_id_added_WHEN_removed_to_Favourite_THEN_it_no_longer_can_be_read_out() =
|
||||||
|
runBlocking {
|
||||||
|
val expected = listOf<ContentId>()
|
||||||
|
sut.markAsFavourite(ContentId("b"))
|
||||||
|
|
||||||
|
sut.deleteAsFavourite(ContentId("b"))
|
||||||
|
val actual = sut.observeFavourites().first()
|
||||||
|
|
||||||
|
Assert.assertEquals(expected, actual)
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun GIVEN_empty_database_WHILE_observing_content_WHEN_favourite_added_THEN_change_is_emitted() =
|
||||||
|
runBlocking<Unit> {
|
||||||
|
val expected = listOf(listOf(), listOf(ContentId("a")))
|
||||||
|
|
||||||
|
val testDispatcher = TestCoroutineDispatcher()
|
||||||
|
val actual = async(testDispatcher) {
|
||||||
|
sut.observeFavourites().take(2).toList()
|
||||||
|
}
|
||||||
|
testDispatcher.advanceUntilIdle()
|
||||||
|
|
||||||
|
sut.markAsFavourite(ContentId("a"))
|
||||||
|
|
||||||
|
Assert.assertEquals(expected, actual.await())
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun GIVEN_non_empty_database_WHILE_observing_content_WHEN_favourite_removed_THEN_change_is_emitted() =
|
||||||
|
runBlocking<Unit> {
|
||||||
|
val expected = listOf(listOf(ContentId("a")), listOf())
|
||||||
|
sut.markAsFavourite(ContentId("a"))
|
||||||
|
|
||||||
|
val testDispatcher = TestCoroutineDispatcher()
|
||||||
|
val actual = async(testDispatcher) {
|
||||||
|
sut.observeFavourites().take(2).toList()
|
||||||
|
}
|
||||||
|
testDispatcher.advanceUntilIdle()
|
||||||
|
|
||||||
|
sut.deleteAsFavourite(ContentId("a"))
|
||||||
|
|
||||||
|
Assert.assertEquals(expected, actual.await())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,4 @@
|
||||||
|
sdk=28
|
||||||
|
shadows=org.fnives.test.showcase.testutils.shadow.ShadowSnackbar
|
||||||
|
instrumentedPackages=androidx.loader.content
|
||||||
|
application=dagger.hilt.android.testing.HiltTestApplication
|
||||||
|
|
@ -1,33 +1,29 @@
|
||||||
package org.fnives.test.showcase.testutils
|
package org.fnives.test.showcase.testutils
|
||||||
|
|
||||||
import androidx.test.core.app.ApplicationProvider
|
//import org.fnives.test.showcase.di.createAppModules
|
||||||
import org.fnives.test.showcase.TestShowcaseApplication
|
//import org.koin.android.ext.koin.androidContext
|
||||||
import org.fnives.test.showcase.di.BaseUrlProvider
|
|
||||||
import org.fnives.test.showcase.di.createAppModules
|
|
||||||
import org.junit.rules.TestRule
|
import org.junit.rules.TestRule
|
||||||
import org.junit.runner.Description
|
import org.junit.runner.Description
|
||||||
import org.junit.runners.model.Statement
|
import org.junit.runners.model.Statement
|
||||||
import org.koin.android.ext.koin.androidContext
|
//import org.koin.core.context.GlobalContext
|
||||||
import org.koin.core.context.GlobalContext
|
//import org.koin.core.context.startKoin
|
||||||
import org.koin.core.context.startKoin
|
|
||||||
import org.koin.core.context.stopKoin
|
|
||||||
|
|
||||||
class ReloadKoinModulesIfNecessaryTestRule : TestRule {
|
class ReloadKoinModulesIfNecessaryTestRule : TestRule {
|
||||||
override fun apply(base: Statement, description: Description): Statement =
|
override fun apply(base: Statement, description: Description): Statement =
|
||||||
object : Statement() {
|
object : Statement() {
|
||||||
override fun evaluate() {
|
override fun evaluate() {
|
||||||
if (GlobalContext.getOrNull() == null) {
|
// if (GlobalContext.getOrNull() == null) {
|
||||||
val application = ApplicationProvider.getApplicationContext<TestShowcaseApplication>()
|
// val application = ApplicationProvider.getApplicationContext<TestShowcaseApplication>()
|
||||||
startKoin {
|
// startKoin {
|
||||||
androidContext(application)
|
// androidContext(application)
|
||||||
modules(createAppModules(BaseUrlProvider.get()))
|
// modules(createAppModules(BaseUrlProvider.get()))
|
||||||
}
|
// }
|
||||||
}
|
}
|
||||||
try {
|
// try {
|
||||||
base.evaluate()
|
// base.evaluate()
|
||||||
} finally {
|
// } finally {
|
||||||
stopKoin()
|
// stopKoin()
|
||||||
}
|
// }
|
||||||
}
|
// }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,6 @@
|
||||||
package org.fnives.test.showcase.di
|
package org.fnives.test.showcase.di
|
||||||
|
|
||||||
import android.content.Context
|
import android.content.Context
|
||||||
import org.fnives.test.showcase.model.network.BaseUrl
|
|
||||||
import org.fnives.test.showcase.testutils.TestMainDispatcher
|
import org.fnives.test.showcase.testutils.TestMainDispatcher
|
||||||
import org.fnives.test.showcase.ui.auth.AuthViewModel
|
import org.fnives.test.showcase.ui.auth.AuthViewModel
|
||||||
import org.fnives.test.showcase.ui.home.MainViewModel
|
import org.fnives.test.showcase.ui.home.MainViewModel
|
||||||
|
|
@ -10,11 +9,8 @@ import org.junit.jupiter.api.AfterEach
|
||||||
import org.junit.jupiter.api.BeforeEach
|
import org.junit.jupiter.api.BeforeEach
|
||||||
import org.junit.jupiter.api.Test
|
import org.junit.jupiter.api.Test
|
||||||
import org.junit.jupiter.api.extension.ExtendWith
|
import org.junit.jupiter.api.extension.ExtendWith
|
||||||
import org.koin.android.ext.koin.androidContext
|
|
||||||
import org.koin.core.context.startKoin
|
|
||||||
import org.koin.core.context.stopKoin
|
import org.koin.core.context.stopKoin
|
||||||
import org.koin.test.KoinTest
|
import org.koin.test.KoinTest
|
||||||
import org.koin.test.check.checkModules
|
|
||||||
import org.koin.test.inject
|
import org.koin.test.inject
|
||||||
import org.mockito.kotlin.anyOrNull
|
import org.mockito.kotlin.anyOrNull
|
||||||
import org.mockito.kotlin.doReturn
|
import org.mockito.kotlin.doReturn
|
||||||
|
|
@ -42,20 +38,20 @@ class DITest : KoinTest {
|
||||||
fun verifyStaticModules() {
|
fun verifyStaticModules() {
|
||||||
val mockContext = mock<Context>()
|
val mockContext = mock<Context>()
|
||||||
whenever(mockContext.getSharedPreferences(anyOrNull(), anyOrNull())).doReturn(mock())
|
whenever(mockContext.getSharedPreferences(anyOrNull(), anyOrNull())).doReturn(mock())
|
||||||
checkModules {
|
// checkModules {
|
||||||
androidContext(mockContext)
|
// androidContext(mockContext)
|
||||||
modules(createAppModules(BaseUrl("https://a.com/")))
|
// modules(createAppModules(BaseUrl("https://a.com/")))
|
||||||
}
|
// }
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
fun verifyViewModelModules() {
|
fun verifyViewModelModules() {
|
||||||
val mockContext = mock<Context>()
|
val mockContext = mock<Context>()
|
||||||
whenever(mockContext.getSharedPreferences(anyOrNull(), anyOrNull())).doReturn(mock())
|
whenever(mockContext.getSharedPreferences(anyOrNull(), anyOrNull())).doReturn(mock())
|
||||||
startKoin {
|
// startKoin {
|
||||||
androidContext(mockContext)
|
// androidContext(mockContext)
|
||||||
modules(createAppModules(BaseUrl("https://a.com/")))
|
// modules(createAppModules(BaseUrl("https://a.com/")))
|
||||||
}
|
// }
|
||||||
authViewModel
|
authViewModel
|
||||||
mainViewModel
|
mainViewModel
|
||||||
splashViewModel
|
splashViewModel
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue