Add Hilt(Dagger) example of android/shared tests
This commit is contained in:
parent
e8d0c746b9
commit
e4f42baaed
34 changed files with 840 additions and 91 deletions
|
|
@ -32,6 +32,7 @@ android {
|
|||
hilt {
|
||||
dimension 'di'
|
||||
applicationId "org.fnives.test.showcase.hilt"
|
||||
testInstrumentationRunner "org.fnives.test.showcase.testutils.configuration.HiltTestRunner"
|
||||
}
|
||||
koin {
|
||||
dimension 'di'
|
||||
|
|
@ -47,15 +48,24 @@ android {
|
|||
androidTest {
|
||||
java.srcDirs += "src/sharedTest/java"
|
||||
}
|
||||
androidTestHilt {
|
||||
java.srcDirs += "src/sharedTestHilt/java"
|
||||
}
|
||||
androidTestKoin {
|
||||
java.srcDirs += "src/sharedTestKoin/java"
|
||||
}
|
||||
|
||||
test {
|
||||
java.srcDirs += "src/sharedTest/java"
|
||||
java.srcDirs += "src/robolectricTest/java"
|
||||
}
|
||||
testHilt {
|
||||
java.srcDirs += "src/sharedTestHilt/java"
|
||||
java.srcDirs += "src/robolectricTestHilt/java"
|
||||
resources.srcDirs += "src/robolectricTestHilt/resources"
|
||||
}
|
||||
testKoin {
|
||||
java.srcDirs += "src/sharedTestKoin/java"
|
||||
java.srcDirs += "src/robolectricTestKoin/java"
|
||||
}
|
||||
}
|
||||
|
|
@ -147,4 +157,5 @@ dependencies {
|
|||
androidTestRuntimeOnly "org.junit.vintage:junit-vintage-engine:$testing_junit5_version"
|
||||
androidTestImplementation "com.google.dagger:hilt-android-testing:$hilt_version"
|
||||
kaptAndroidTest "com.google.dagger:hilt-compiler:$hilt_version"
|
||||
androidTestImplementation project(":network") // hilt needs it
|
||||
}
|
||||
|
|
@ -0,0 +1,14 @@
|
|||
package org.fnives.test.showcase.testutils.configuration
|
||||
|
||||
import org.fnives.test.showcase.network.mockserver.MockServerScenarioSetup
|
||||
|
||||
object AndroidTestServerTypeConfiguration : ServerTypeConfiguration {
|
||||
override val useHttps: Boolean get() = true
|
||||
|
||||
override val url: String get() = "${MockServerScenarioSetup.HTTPS_BASE_URL}:${MockServerScenarioSetup.PORT}/"
|
||||
|
||||
override fun invoke(mockServerScenarioSetup: MockServerScenarioSetup) {
|
||||
val handshakeCertificates = mockServerScenarioSetup.clientCertificates ?: return
|
||||
HttpsConfigurationModule.handshakeCertificates = handshakeCertificates
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,12 @@
|
|||
package org.fnives.test.showcase.testutils.configuration
|
||||
|
||||
import android.app.Application
|
||||
import android.content.Context
|
||||
import androidx.test.runner.AndroidJUnitRunner
|
||||
import dagger.hilt.android.testing.HiltTestApplication
|
||||
|
||||
class HiltTestRunner : AndroidJUnitRunner() {
|
||||
|
||||
override fun newApplication(cl: ClassLoader?, name: String?, context: Context?): Application =
|
||||
super.newApplication(cl, HiltTestApplication::class.java.name, context)
|
||||
}
|
||||
|
|
@ -0,0 +1,33 @@
|
|||
package org.fnives.test.showcase.testutils.configuration
|
||||
|
||||
import dagger.Module
|
||||
import dagger.Provides
|
||||
import dagger.hilt.components.SingletonComponent
|
||||
import dagger.hilt.testing.TestInstallIn
|
||||
import okhttp3.tls.HandshakeCertificates
|
||||
import org.fnives.test.showcase.hilt.SessionLessQualifier
|
||||
import org.fnives.test.showcase.network.di.hilt.BindsBaseOkHttpClient
|
||||
import org.fnives.test.showcase.network.di.hilt.HiltNetworkModule
|
||||
import javax.inject.Singleton
|
||||
|
||||
@Module
|
||||
@TestInstallIn(
|
||||
components = [SingletonComponent::class],
|
||||
replaces = [BindsBaseOkHttpClient::class]
|
||||
)
|
||||
object HttpsConfigurationModule {
|
||||
|
||||
lateinit var handshakeCertificates: HandshakeCertificates
|
||||
|
||||
@Provides
|
||||
@Singleton
|
||||
@SessionLessQualifier
|
||||
fun bindsBaseOkHttpClient(enableLogging: Boolean) =
|
||||
HiltNetworkModule.provideSessionLessOkHttpClient(enableLogging)
|
||||
.newBuilder()
|
||||
.sslSocketFactory(
|
||||
handshakeCertificates.sslSocketFactory(),
|
||||
handshakeCertificates.trustManager
|
||||
)
|
||||
.build()
|
||||
}
|
||||
|
|
@ -1,29 +0,0 @@
|
|||
package org.fnives.test.showcase.testutils
|
||||
|
||||
//import org.fnives.test.showcase.di.createAppModules
|
||||
//import org.koin.android.ext.koin.androidContext
|
||||
import org.junit.rules.TestRule
|
||||
import org.junit.runner.Description
|
||||
import org.junit.runners.model.Statement
|
||||
//import org.koin.core.context.GlobalContext
|
||||
//import org.koin.core.context.startKoin
|
||||
|
||||
class ReloadKoinModulesIfNecessaryTestRule : TestRule {
|
||||
override fun apply(base: Statement, description: Description): Statement =
|
||||
object : Statement() {
|
||||
override fun evaluate() {
|
||||
// if (GlobalContext.getOrNull() == null) {
|
||||
// val application = ApplicationProvider.getApplicationContext<TestShowcaseApplication>()
|
||||
// startKoin {
|
||||
// androidContext(application)
|
||||
// modules(createAppModules(BaseUrlProvider.get()))
|
||||
// }
|
||||
}
|
||||
// try {
|
||||
// base.evaluate()
|
||||
// } finally {
|
||||
// stopKoin()
|
||||
// }
|
||||
// }
|
||||
}
|
||||
}
|
||||
|
|
@ -1,31 +1,31 @@
|
|||
package org.fnives.test.showcase.testutils.statesetup
|
||||
|
||||
import kotlinx.coroutines.runBlocking
|
||||
import org.fnives.test.showcase.core.login.IsUserLoggedInUseCase
|
||||
import org.fnives.test.showcase.core.login.LoginUseCase
|
||||
import org.fnives.test.showcase.core.login.LogoutUseCase
|
||||
import org.fnives.test.showcase.model.auth.LoginCredentials
|
||||
import org.fnives.test.showcase.network.mockserver.MockServerScenarioSetup
|
||||
import org.fnives.test.showcase.network.mockserver.scenario.auth.AuthScenario
|
||||
import org.koin.test.KoinTest
|
||||
import org.koin.test.get
|
||||
|
||||
object SetupLoggedInState : KoinTest {
|
||||
|
||||
private val logoutUseCase get() = get<LogoutUseCase>()
|
||||
private val loginUseCase get() = get<LoginUseCase>()
|
||||
private val isUserLoggedInUseCase get() = get<IsUserLoggedInUseCase>()
|
||||
|
||||
fun setupLogin(mockServerScenarioSetup: MockServerScenarioSetup) {
|
||||
mockServerScenarioSetup.setScenario(AuthScenario.Success("a", "b"))
|
||||
runBlocking {
|
||||
loginUseCase.invoke(LoginCredentials("a", "b"))
|
||||
}
|
||||
}
|
||||
|
||||
fun isLoggedIn() = isUserLoggedInUseCase.invoke()
|
||||
|
||||
fun setupLogout() {
|
||||
runBlocking { logoutUseCase.invoke() }
|
||||
}
|
||||
}
|
||||
//package org.fnives.test.showcase.testutils.statesetup
|
||||
//
|
||||
//import kotlinx.coroutines.runBlocking
|
||||
//import org.fnives.test.showcase.core.login.IsUserLoggedInUseCase
|
||||
//import org.fnives.test.showcase.core.login.LoginUseCase
|
||||
//import org.fnives.test.showcase.core.login.LogoutUseCase
|
||||
//import org.fnives.test.showcase.model.auth.LoginCredentials
|
||||
//import org.fnives.test.showcase.network.mockserver.MockServerScenarioSetup
|
||||
//import org.fnives.test.showcase.network.mockserver.scenario.auth.AuthScenario
|
||||
//import org.koin.test.KoinTest
|
||||
//import org.koin.test.get
|
||||
//
|
||||
//object SetupLoggedInState : KoinTest {
|
||||
//
|
||||
// private val logoutUseCase get() = get<LogoutUseCase>()
|
||||
// private val loginUseCase get() = get<LoginUseCase>()
|
||||
// private val isUserLoggedInUseCase get() = get<IsUserLoggedInUseCase>()
|
||||
//
|
||||
// fun setupLogin(mockServerScenarioSetup: MockServerScenarioSetup) {
|
||||
// mockServerScenarioSetup.setScenario(AuthScenario.Success("a", "b"))
|
||||
// runBlocking {
|
||||
// loginUseCase.invoke(LoginCredentials("a", "b"))
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// fun isLoggedIn() = isUserLoggedInUseCase.invoke()
|
||||
//
|
||||
// fun setupLogout() {
|
||||
// runBlocking { logoutUseCase.invoke() }
|
||||
// }
|
||||
//}
|
||||
|
|
|
|||
|
|
@ -21,14 +21,14 @@ import org.fnives.test.showcase.testutils.robot.Robot
|
|||
import org.fnives.test.showcase.testutils.viewactions.PullToRefresh
|
||||
import org.fnives.test.showcase.testutils.viewactions.WithDrawable
|
||||
import org.fnives.test.showcase.testutils.viewactions.notIntended
|
||||
import org.fnives.test.showcase.ui.auth.AuthActivity
|
||||
import org.fnives.test.showcase.ui.ActivityClassHolder
|
||||
import org.hamcrest.Matchers.allOf
|
||||
|
||||
class HomeRobot : Robot {
|
||||
|
||||
override fun init() {
|
||||
Intents.init()
|
||||
Intents.intending(IntentMatchers.hasComponent(AuthActivity::class.java.canonicalName))
|
||||
Intents.intending(IntentMatchers.hasComponent(ActivityClassHolder.authActivity().java.canonicalName))
|
||||
.respondWith(Instrumentation.ActivityResult(0, null))
|
||||
}
|
||||
|
||||
|
|
@ -37,11 +37,11 @@ class HomeRobot : Robot {
|
|||
}
|
||||
|
||||
fun assertNavigatedToAuth() = apply {
|
||||
Intents.intended(IntentMatchers.hasComponent(AuthActivity::class.java.canonicalName))
|
||||
Intents.intended(IntentMatchers.hasComponent(ActivityClassHolder.authActivity().java.canonicalName))
|
||||
}
|
||||
|
||||
fun assertDidNotNavigateToAuth() = apply {
|
||||
notIntended(IntentMatchers.hasComponent(AuthActivity::class.java.canonicalName))
|
||||
notIntended(IntentMatchers.hasComponent(ActivityClassHolder.authActivity().java.canonicalName))
|
||||
}
|
||||
|
||||
fun clickSignOut() = apply {
|
||||
|
|
|
|||
|
|
@ -21,7 +21,7 @@ import org.fnives.test.showcase.testutils.configuration.SpecificTestConfiguratio
|
|||
import org.fnives.test.showcase.testutils.configuration.TestConfigurationsFactory
|
||||
import org.fnives.test.showcase.testutils.robot.Robot
|
||||
import org.fnives.test.showcase.testutils.viewactions.notIntended
|
||||
import org.fnives.test.showcase.ui.home.MainActivity
|
||||
import org.fnives.test.showcase.ui.ActivityClassHolder
|
||||
import org.hamcrest.core.IsNot.not
|
||||
|
||||
class LoginRobot(
|
||||
|
|
@ -37,7 +37,7 @@ class LoginRobot(
|
|||
|
||||
override fun init() {
|
||||
Intents.init()
|
||||
intending(hasComponent(MainActivity::class.java.canonicalName))
|
||||
intending(hasComponent(ActivityClassHolder.mainActivity().java.canonicalName))
|
||||
.respondWith(Instrumentation.ActivityResult(Activity.RESULT_OK, Intent()))
|
||||
}
|
||||
|
||||
|
|
@ -91,10 +91,10 @@ class LoginRobot(
|
|||
}
|
||||
|
||||
fun assertNavigatedToHome() = apply {
|
||||
intended(hasComponent(MainActivity::class.java.canonicalName))
|
||||
intended(hasComponent(ActivityClassHolder.mainActivity().java.canonicalName))
|
||||
}
|
||||
|
||||
fun assertNotNavigatedToHome() = apply {
|
||||
notIntended(hasComponent(MainActivity::class.java.canonicalName))
|
||||
notIntended(hasComponent(ActivityClassHolder.mainActivity().java.canonicalName))
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -5,16 +5,15 @@ import androidx.test.espresso.intent.Intents
|
|||
import androidx.test.espresso.intent.matcher.IntentMatchers
|
||||
import org.fnives.test.showcase.testutils.robot.Robot
|
||||
import org.fnives.test.showcase.testutils.viewactions.notIntended
|
||||
import org.fnives.test.showcase.ui.auth.AuthActivity
|
||||
import org.fnives.test.showcase.ui.home.MainActivity
|
||||
import org.fnives.test.showcase.ui.ActivityClassHolder
|
||||
|
||||
class SplashRobot : Robot {
|
||||
|
||||
override fun init() {
|
||||
Intents.init()
|
||||
Intents.intending(IntentMatchers.hasComponent(MainActivity::class.java.canonicalName))
|
||||
Intents.intending(IntentMatchers.hasComponent(ActivityClassHolder.mainActivity().java.canonicalName))
|
||||
.respondWith(Instrumentation.ActivityResult(0, null))
|
||||
Intents.intending(IntentMatchers.hasComponent(AuthActivity::class.java.canonicalName))
|
||||
Intents.intending(IntentMatchers.hasComponent(ActivityClassHolder.authActivity().java.canonicalName))
|
||||
.respondWith(Instrumentation.ActivityResult(0, null))
|
||||
}
|
||||
|
||||
|
|
@ -23,18 +22,18 @@ class SplashRobot : Robot {
|
|||
}
|
||||
|
||||
fun assertHomeIsStarted() = apply {
|
||||
Intents.intended(IntentMatchers.hasComponent(MainActivity::class.java.canonicalName))
|
||||
Intents.intended(IntentMatchers.hasComponent(ActivityClassHolder.mainActivity().java.canonicalName))
|
||||
}
|
||||
|
||||
fun assertHomeIsNotStarted() = apply {
|
||||
notIntended(IntentMatchers.hasComponent(MainActivity::class.java.canonicalName))
|
||||
notIntended(IntentMatchers.hasComponent(ActivityClassHolder.mainActivity().java.canonicalName))
|
||||
}
|
||||
|
||||
fun assertAuthIsStarted() = apply {
|
||||
Intents.intended(IntentMatchers.hasComponent(AuthActivity::class.java.canonicalName))
|
||||
Intents.intended(IntentMatchers.hasComponent(ActivityClassHolder.authActivity().java.canonicalName))
|
||||
}
|
||||
|
||||
fun assertAuthIsNotStarted() = apply {
|
||||
notIntended(IntentMatchers.hasComponent(AuthActivity::class.java.canonicalName))
|
||||
notIntended(IntentMatchers.hasComponent(ActivityClassHolder.authActivity().java.canonicalName))
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,42 @@
|
|||
package org.fnives.test.showcase.testutils.idling
|
||||
|
||||
import androidx.annotation.CheckResult
|
||||
import androidx.test.espresso.IdlingResource
|
||||
import com.jakewharton.espresso.OkHttp3IdlingResource
|
||||
import okhttp3.OkHttpClient
|
||||
import org.fnives.test.showcase.hilt.SessionLessQualifier
|
||||
import org.fnives.test.showcase.hilt.SessionQualifier
|
||||
import javax.inject.Inject
|
||||
|
||||
class NetworkSynchronization @Inject constructor(
|
||||
@SessionQualifier
|
||||
private val sessionOkhttpClient: OkHttpClient,
|
||||
@SessionLessQualifier
|
||||
private val sessionlessOkhttpClient: OkHttpClient
|
||||
) {
|
||||
|
||||
@CheckResult
|
||||
fun registerNetworkingSynchronization(): Disposable {
|
||||
val idlingResources = OkHttpClientTypes.values()
|
||||
.map { it to getOkHttpClient(it) }
|
||||
.associateBy { it.second.dispatcher }
|
||||
.values
|
||||
.map { (key, client) -> client.asIdlingResource(key.qualifier) }
|
||||
.map(::IdlingResourceDisposable)
|
||||
|
||||
return CompositeDisposable(idlingResources)
|
||||
}
|
||||
|
||||
private fun getOkHttpClient(type: OkHttpClientTypes): OkHttpClient =
|
||||
when (type) {
|
||||
OkHttpClientTypes.SESSION -> sessionOkhttpClient
|
||||
OkHttpClientTypes.SESSIONLESS -> sessionlessOkhttpClient
|
||||
}
|
||||
|
||||
private fun OkHttpClient.asIdlingResource(name: String): IdlingResource =
|
||||
OkHttp3IdlingResource.create(name, this)
|
||||
|
||||
enum class OkHttpClientTypes(val qualifier: String) {
|
||||
SESSION("SESSION-NETWORKING"), SESSIONLESS("SESSIONLESS-NETWORKING")
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,30 @@
|
|||
package org.fnives.test.showcase.testutils.statesetup
|
||||
|
||||
import kotlinx.coroutines.runBlocking
|
||||
import org.fnives.test.showcase.core.login.IsUserLoggedInUseCase
|
||||
import org.fnives.test.showcase.core.login.LoginUseCase
|
||||
import org.fnives.test.showcase.core.login.LogoutUseCase
|
||||
import org.fnives.test.showcase.model.auth.LoginCredentials
|
||||
import org.fnives.test.showcase.network.mockserver.MockServerScenarioSetup
|
||||
import org.fnives.test.showcase.network.mockserver.scenario.auth.AuthScenario
|
||||
import javax.inject.Inject
|
||||
|
||||
class SetupLoggedInState @Inject constructor(
|
||||
private val logoutUseCase : LogoutUseCase,
|
||||
private val loginUseCase : LoginUseCase,
|
||||
private val isUserLoggedInUseCase: IsUserLoggedInUseCase
|
||||
) {
|
||||
|
||||
fun setupLogin(mockServerScenarioSetup: MockServerScenarioSetup) {
|
||||
mockServerScenarioSetup.setScenario(AuthScenario.Success("a", "b"))
|
||||
runBlocking {
|
||||
loginUseCase.invoke(LoginCredentials("a", "b"))
|
||||
}
|
||||
}
|
||||
|
||||
fun isLoggedIn() = isUserLoggedInUseCase.invoke()
|
||||
|
||||
fun setupLogout() {
|
||||
runBlocking { logoutUseCase.invoke() }
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,14 @@
|
|||
package org.fnives.test.showcase.ui
|
||||
|
||||
import org.fnives.test.showcase.ui.auth.HiltAuthActivity
|
||||
import org.fnives.test.showcase.ui.home.HiltMainActivity
|
||||
import org.fnives.test.showcase.ui.splash.HiltSplashActivity
|
||||
|
||||
object ActivityClassHolder {
|
||||
|
||||
fun authActivity() = HiltAuthActivity::class
|
||||
|
||||
fun mainActivity() = HiltMainActivity::class
|
||||
|
||||
fun splashActivity() = HiltSplashActivity::class
|
||||
}
|
||||
|
|
@ -0,0 +1,248 @@
|
|||
package org.fnives.test.showcase.ui.home
|
||||
|
||||
import androidx.arch.core.executor.testing.InstantTaskExecutorRule
|
||||
import androidx.lifecycle.Lifecycle
|
||||
import androidx.test.core.app.ActivityScenario
|
||||
import androidx.test.ext.junit.runners.AndroidJUnit4
|
||||
import dagger.hilt.android.testing.HiltAndroidRule
|
||||
import dagger.hilt.android.testing.HiltAndroidTest
|
||||
import org.fnives.test.showcase.model.content.FavouriteContent
|
||||
import org.fnives.test.showcase.network.mockserver.ContentData
|
||||
import org.fnives.test.showcase.network.mockserver.scenario.content.ContentScenario
|
||||
import org.fnives.test.showcase.network.mockserver.scenario.refresh.RefreshTokenScenario
|
||||
import org.fnives.test.showcase.testutils.MockServerScenarioSetupTestRule
|
||||
import org.fnives.test.showcase.testutils.configuration.SpecificTestConfigurationsFactory
|
||||
import org.fnives.test.showcase.testutils.idling.Disposable
|
||||
import org.fnives.test.showcase.testutils.idling.NetworkSynchronization
|
||||
import org.fnives.test.showcase.testutils.idling.loopMainThreadFor
|
||||
import org.fnives.test.showcase.testutils.idling.loopMainThreadUntilIdleWithIdlingResources
|
||||
import org.fnives.test.showcase.testutils.robot.RobotTestRule
|
||||
import org.fnives.test.showcase.testutils.statesetup.SetupLoggedInState
|
||||
import org.junit.After
|
||||
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")
|
||||
@RunWith(AndroidJUnit4::class)
|
||||
@HiltAndroidTest
|
||||
class MainActivityTest {
|
||||
|
||||
private lateinit var activityScenario: ActivityScenario<HiltMainActivity>
|
||||
|
||||
@Rule
|
||||
@JvmField
|
||||
val instantTaskExecutorRule = InstantTaskExecutorRule()
|
||||
|
||||
@Rule
|
||||
@JvmField
|
||||
val snackbarVerificationTestRule = SpecificTestConfigurationsFactory.createSnackbarVerification()
|
||||
|
||||
@Rule
|
||||
@JvmField
|
||||
val robotRule = RobotTestRule(HomeRobot())
|
||||
private val homeRobot get() = robotRule.robot
|
||||
|
||||
@Rule
|
||||
@JvmField
|
||||
val mockServerScenarioSetupTestRule = MockServerScenarioSetupTestRule()
|
||||
|
||||
@Rule
|
||||
@JvmField
|
||||
val mainDispatcherTestRule = SpecificTestConfigurationsFactory.createMainDispatcherTestRule()
|
||||
|
||||
@Rule
|
||||
@JvmField
|
||||
val hiltRule = HiltAndroidRule(this)
|
||||
|
||||
@Inject
|
||||
lateinit var setupLoggedInState: SetupLoggedInState
|
||||
|
||||
@Inject
|
||||
lateinit var networkSynchronization: NetworkSynchronization
|
||||
|
||||
private lateinit var disposable: Disposable
|
||||
|
||||
@Before
|
||||
fun setUp() {
|
||||
SpecificTestConfigurationsFactory.createServerTypeConfiguration()
|
||||
.invoke(mockServerScenarioSetupTestRule.mockServerScenarioSetup)
|
||||
|
||||
hiltRule.inject()
|
||||
setupLoggedInState.setupLogin(mockServerScenarioSetupTestRule.mockServerScenarioSetup)
|
||||
disposable = networkSynchronization.registerNetworkingSynchronization()
|
||||
}
|
||||
|
||||
@After
|
||||
fun tearDown() {
|
||||
activityScenario.moveToState(Lifecycle.State.DESTROYED)
|
||||
disposable.dispose()
|
||||
}
|
||||
|
||||
@Test
|
||||
fun GIVEN_initialized_MainActivity_WHEN_signout_is_clicked_THEN_user_is_signed_out() {
|
||||
mockServerScenarioSetupTestRule.mockServerScenarioSetup
|
||||
.setScenario(ContentScenario.Error(false))
|
||||
activityScenario = ActivityScenario.launch(HiltMainActivity::class.java)
|
||||
mainDispatcherTestRule.advanceUntilIdleWithIdlingResources()
|
||||
|
||||
homeRobot.clickSignOut()
|
||||
mainDispatcherTestRule.advanceUntilIdleOrActivityIsDestroyed()
|
||||
|
||||
homeRobot.assertNavigatedToAuth()
|
||||
Assert.assertEquals(false, setupLoggedInState.isLoggedIn())
|
||||
}
|
||||
|
||||
@Test
|
||||
fun GIVEN_success_response_WHEN_data_is_returned_THEN_it_is_shown_on_the_ui() {
|
||||
mockServerScenarioSetupTestRule.mockServerScenarioSetup
|
||||
.setScenario(ContentScenario.Success(false))
|
||||
activityScenario = ActivityScenario.launch(HiltMainActivity::class.java)
|
||||
|
||||
mainDispatcherTestRule.advanceUntilIdleWithIdlingResources()
|
||||
ContentData.contentSuccess.forEach {
|
||||
homeRobot.assertContainsItem(FavouriteContent(it, false))
|
||||
}
|
||||
homeRobot.assertDidNotNavigateToAuth()
|
||||
}
|
||||
|
||||
@Test
|
||||
fun GIVEN_success_response_WHEN_item_is_clicked_THEN_ui_is_updated() {
|
||||
mockServerScenarioSetupTestRule.mockServerScenarioSetup
|
||||
.setScenario(ContentScenario.Success(false))
|
||||
activityScenario = ActivityScenario.launch(HiltMainActivity::class.java)
|
||||
|
||||
mainDispatcherTestRule.advanceUntilIdleWithIdlingResources()
|
||||
homeRobot.clickOnContentItem(ContentData.contentSuccess.first())
|
||||
mainDispatcherTestRule.advanceUntilIdleWithIdlingResources()
|
||||
|
||||
val expectedItem = FavouriteContent(ContentData.contentSuccess.first(), true)
|
||||
homeRobot.assertContainsItem(expectedItem)
|
||||
.assertDidNotNavigateToAuth()
|
||||
}
|
||||
|
||||
@Test
|
||||
fun GIVEN_success_response_WHEN_item_is_clicked_THEN_ui_is_updated_even_if_activity_is_recreated() {
|
||||
mockServerScenarioSetupTestRule.mockServerScenarioSetup
|
||||
.setScenario(ContentScenario.Success(false))
|
||||
activityScenario = ActivityScenario.launch(HiltMainActivity::class.java)
|
||||
|
||||
mainDispatcherTestRule.advanceUntilIdleWithIdlingResources()
|
||||
homeRobot.clickOnContentItem(ContentData.contentSuccess.first())
|
||||
mainDispatcherTestRule.advanceUntilIdleWithIdlingResources()
|
||||
|
||||
val expectedItem = FavouriteContent(ContentData.contentSuccess.first(), true)
|
||||
|
||||
activityScenario.moveToState(Lifecycle.State.DESTROYED)
|
||||
activityScenario = ActivityScenario.launch(HiltMainActivity::class.java)
|
||||
mainDispatcherTestRule.advanceUntilIdleWithIdlingResources()
|
||||
|
||||
homeRobot.assertContainsItem(expectedItem)
|
||||
.assertDidNotNavigateToAuth()
|
||||
}
|
||||
|
||||
@Test
|
||||
fun GIVEN_success_response_WHEN_item_is_clicked_then_clicked_again_THEN_ui_is_updated() {
|
||||
mockServerScenarioSetupTestRule.mockServerScenarioSetup
|
||||
.setScenario(ContentScenario.Success(false))
|
||||
activityScenario = ActivityScenario.launch(HiltMainActivity::class.java)
|
||||
|
||||
mainDispatcherTestRule.advanceUntilIdleWithIdlingResources()
|
||||
homeRobot.clickOnContentItem(ContentData.contentSuccess.first())
|
||||
mainDispatcherTestRule.advanceUntilIdleWithIdlingResources()
|
||||
homeRobot.clickOnContentItem(ContentData.contentSuccess.first())
|
||||
mainDispatcherTestRule.advanceUntilIdleWithIdlingResources()
|
||||
|
||||
val expectedItem = FavouriteContent(ContentData.contentSuccess.first(), false)
|
||||
homeRobot.assertContainsItem(expectedItem)
|
||||
.assertDidNotNavigateToAuth()
|
||||
}
|
||||
|
||||
@Test
|
||||
fun GIVEN_error_response_WHEN_loaded_THEN_error_is_Shown() {
|
||||
mockServerScenarioSetupTestRule.mockServerScenarioSetup
|
||||
.setScenario(ContentScenario.Error(false))
|
||||
activityScenario = ActivityScenario.launch(HiltMainActivity::class.java)
|
||||
mainDispatcherTestRule.advanceUntilIdleWithIdlingResources()
|
||||
|
||||
homeRobot.assertContainsNoItems()
|
||||
.assertContainsError()
|
||||
.assertDidNotNavigateToAuth()
|
||||
}
|
||||
|
||||
@Test
|
||||
fun GIVEN_error_response_then_success_WHEN_retried_THEN_success_is_shown() {
|
||||
mockServerScenarioSetupTestRule.mockServerScenarioSetup
|
||||
.setScenario(
|
||||
ContentScenario.Error(false)
|
||||
.then(ContentScenario.Success(false))
|
||||
)
|
||||
activityScenario = ActivityScenario.launch(HiltMainActivity::class.java)
|
||||
mainDispatcherTestRule.advanceUntilIdleWithIdlingResources()
|
||||
|
||||
homeRobot.swipeRefresh()
|
||||
mainDispatcherTestRule.advanceUntilIdleWithIdlingResources()
|
||||
loopMainThreadFor(2000L)
|
||||
|
||||
ContentData.contentSuccess.forEach {
|
||||
homeRobot.assertContainsItem(FavouriteContent(it, false))
|
||||
}
|
||||
homeRobot.assertDidNotNavigateToAuth()
|
||||
}
|
||||
|
||||
@Test
|
||||
fun GIVEN_success_then_error_WHEN_retried_THEN_error_is_shown() {
|
||||
mockServerScenarioSetupTestRule.mockServerScenarioSetup
|
||||
.setScenario(
|
||||
ContentScenario.Success(false)
|
||||
.then(ContentScenario.Error(false))
|
||||
)
|
||||
activityScenario = ActivityScenario.launch(HiltMainActivity::class.java)
|
||||
mainDispatcherTestRule.advanceUntilIdleWithIdlingResources()
|
||||
|
||||
homeRobot.swipeRefresh()
|
||||
mainDispatcherTestRule.advanceUntilIdleWithIdlingResources()
|
||||
loopMainThreadUntilIdleWithIdlingResources()
|
||||
mainDispatcherTestRule.advanceTimeBy(1000L)
|
||||
loopMainThreadFor(1000)
|
||||
|
||||
homeRobot
|
||||
.assertContainsError()
|
||||
.assertContainsNoItems()
|
||||
.assertDidNotNavigateToAuth()
|
||||
}
|
||||
|
||||
@Test
|
||||
fun GIVEN_unauthenticated_then_success_WHEN_loaded_THEN_success_is_shown() {
|
||||
mockServerScenarioSetupTestRule.mockServerScenarioSetup
|
||||
.setScenario(
|
||||
ContentScenario.Unauthorized(false)
|
||||
.then(ContentScenario.Success(true))
|
||||
)
|
||||
.setScenario(RefreshTokenScenario.Success)
|
||||
|
||||
activityScenario = ActivityScenario.launch(HiltMainActivity::class.java)
|
||||
mainDispatcherTestRule.advanceUntilIdleWithIdlingResources()
|
||||
|
||||
ContentData.contentSuccess.forEach {
|
||||
homeRobot.assertContainsItem(FavouriteContent(it, false))
|
||||
}
|
||||
homeRobot.assertDidNotNavigateToAuth()
|
||||
}
|
||||
|
||||
@Test
|
||||
fun GIVEN_unauthenticated_then_error_WHEN_loaded_THEN_navigated_to_auth() {
|
||||
mockServerScenarioSetupTestRule.mockServerScenarioSetup
|
||||
.setScenario(ContentScenario.Unauthorized(false))
|
||||
.setScenario(RefreshTokenScenario.Error)
|
||||
|
||||
activityScenario = ActivityScenario.launch(HiltMainActivity::class.java)
|
||||
mainDispatcherTestRule.advanceUntilIdleWithIdlingResources()
|
||||
|
||||
homeRobot.assertNavigatedToAuth()
|
||||
Assert.assertEquals(false, setupLoggedInState.isLoggedIn())
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,165 @@
|
|||
package org.fnives.test.showcase.ui.login
|
||||
|
||||
import androidx.arch.core.executor.testing.InstantTaskExecutorRule
|
||||
import androidx.lifecycle.Lifecycle
|
||||
import androidx.test.core.app.ActivityScenario
|
||||
import androidx.test.ext.junit.runners.AndroidJUnit4
|
||||
import dagger.hilt.android.testing.HiltAndroidRule
|
||||
import dagger.hilt.android.testing.HiltAndroidTest
|
||||
import org.fnives.test.showcase.R
|
||||
import org.fnives.test.showcase.network.mockserver.scenario.auth.AuthScenario
|
||||
import org.fnives.test.showcase.testutils.MockServerScenarioSetupTestRule
|
||||
import org.fnives.test.showcase.testutils.configuration.SpecificTestConfigurationsFactory
|
||||
import org.fnives.test.showcase.testutils.idling.Disposable
|
||||
import org.fnives.test.showcase.testutils.idling.NetworkSynchronization
|
||||
import org.fnives.test.showcase.testutils.robot.RobotTestRule
|
||||
import org.fnives.test.showcase.ui.auth.HiltAuthActivity
|
||||
import org.junit.After
|
||||
import org.junit.Before
|
||||
import org.junit.Rule
|
||||
import org.junit.Test
|
||||
import org.junit.runner.RunWith
|
||||
import javax.inject.Inject
|
||||
|
||||
@Suppress("TestFunctionName")
|
||||
@RunWith(AndroidJUnit4::class)
|
||||
@HiltAndroidTest
|
||||
class AuthActivityTest {
|
||||
|
||||
private lateinit var activityScenario: ActivityScenario<HiltAuthActivity>
|
||||
|
||||
@Rule
|
||||
@JvmField
|
||||
val instantTaskExecutorRule = InstantTaskExecutorRule()
|
||||
|
||||
@Rule
|
||||
@JvmField
|
||||
val snackbarVerificationTestRule = SpecificTestConfigurationsFactory.createSnackbarVerification()
|
||||
|
||||
@Rule
|
||||
@JvmField
|
||||
val robotRule = RobotTestRule(LoginRobot())
|
||||
private val loginRobot get() = robotRule.robot
|
||||
|
||||
@Rule
|
||||
@JvmField
|
||||
val mockServerScenarioSetupTestRule = MockServerScenarioSetupTestRule()
|
||||
|
||||
@Rule
|
||||
@JvmField
|
||||
val mainDispatcherTestRule = SpecificTestConfigurationsFactory.createMainDispatcherTestRule()
|
||||
|
||||
@Rule
|
||||
@JvmField
|
||||
val hiltRule = HiltAndroidRule(this)
|
||||
|
||||
@Inject
|
||||
lateinit var networkSynchronization: NetworkSynchronization
|
||||
|
||||
private lateinit var disposable: Disposable
|
||||
|
||||
@Before
|
||||
fun setUp() {
|
||||
SpecificTestConfigurationsFactory.createServerTypeConfiguration()
|
||||
.invoke(mockServerScenarioSetupTestRule.mockServerScenarioSetup)
|
||||
hiltRule.inject()
|
||||
disposable = networkSynchronization.registerNetworkingSynchronization()
|
||||
}
|
||||
|
||||
@After
|
||||
fun tearDown() {
|
||||
activityScenario.moveToState(Lifecycle.State.DESTROYED)
|
||||
disposable.dispose()
|
||||
}
|
||||
|
||||
@Test
|
||||
fun GIVEN_non_empty_password_and_username_and_successful_response_WHEN_signIn_THEN_no_error_is_shown_and_navigating_to_home() {
|
||||
mockServerScenarioSetupTestRule.mockServerScenarioSetup.setScenario(
|
||||
AuthScenario.Success(
|
||||
password = "alma",
|
||||
username = "banan"
|
||||
)
|
||||
)
|
||||
activityScenario = ActivityScenario.launch(HiltAuthActivity::class.java)
|
||||
loginRobot
|
||||
.setPassword("alma")
|
||||
.setUsername("banan")
|
||||
.assertPassword("alma")
|
||||
.assertUsername("banan")
|
||||
.clickOnLogin()
|
||||
.assertLoadingBeforeRequests()
|
||||
|
||||
mainDispatcherTestRule.advanceUntilIdleOrActivityIsDestroyed()
|
||||
loginRobot.assertNavigatedToHome()
|
||||
}
|
||||
|
||||
@Test
|
||||
fun GIVEN_empty_password_and_username_WHEN_signIn_THEN_error_password_is_shown() {
|
||||
activityScenario = ActivityScenario.launch(HiltAuthActivity::class.java)
|
||||
loginRobot
|
||||
.setUsername("banan")
|
||||
.assertUsername("banan")
|
||||
.clickOnLogin()
|
||||
.assertLoadingBeforeRequests()
|
||||
|
||||
mainDispatcherTestRule.advanceUntilIdleWithIdlingResources()
|
||||
loginRobot.assertErrorIsShown(R.string.password_is_invalid)
|
||||
.assertNotNavigatedToHome()
|
||||
.assertNotLoading()
|
||||
}
|
||||
|
||||
@Test
|
||||
fun GIVEN_password_and_empty_username_WHEN_signIn_THEN_error_username_is_shown() {
|
||||
activityScenario = ActivityScenario.launch(HiltAuthActivity::class.java)
|
||||
loginRobot
|
||||
.setPassword("banan")
|
||||
.assertPassword("banan")
|
||||
.clickOnLogin()
|
||||
.assertLoadingBeforeRequests()
|
||||
|
||||
mainDispatcherTestRule.advanceUntilIdleWithIdlingResources()
|
||||
loginRobot.assertErrorIsShown(R.string.username_is_invalid)
|
||||
.assertNotNavigatedToHome()
|
||||
.assertNotLoading()
|
||||
}
|
||||
|
||||
@Test
|
||||
fun GIVEN_password_and_username_and_invalid_credentials_response_WHEN_signIn_THEN_error_invalid_credentials_is_shown() {
|
||||
mockServerScenarioSetupTestRule.mockServerScenarioSetup.setScenario(
|
||||
AuthScenario.InvalidCredentials(username = "alma", password = "banan")
|
||||
)
|
||||
activityScenario = ActivityScenario.launch(HiltAuthActivity::class.java)
|
||||
loginRobot
|
||||
.setUsername("alma")
|
||||
.setPassword("banan")
|
||||
.assertUsername("alma")
|
||||
.assertPassword("banan")
|
||||
.clickOnLogin()
|
||||
.assertLoadingBeforeRequests()
|
||||
|
||||
mainDispatcherTestRule.advanceUntilIdleWithIdlingResources()
|
||||
loginRobot.assertErrorIsShown(R.string.credentials_invalid)
|
||||
.assertNotNavigatedToHome()
|
||||
.assertNotLoading()
|
||||
}
|
||||
|
||||
@Test
|
||||
fun GIVEN_password_and_username_and_error_response_WHEN_signIn_THEN_error_invalid_credentials_is_shown() {
|
||||
mockServerScenarioSetupTestRule.mockServerScenarioSetup.setScenario(
|
||||
AuthScenario.GenericError(username = "alma", password = "banan")
|
||||
)
|
||||
activityScenario = ActivityScenario.launch(HiltAuthActivity::class.java)
|
||||
loginRobot
|
||||
.setUsername("alma")
|
||||
.setPassword("banan")
|
||||
.assertUsername("alma")
|
||||
.assertPassword("banan")
|
||||
.clickOnLogin()
|
||||
.assertLoadingBeforeRequests()
|
||||
|
||||
mainDispatcherTestRule.advanceUntilIdleWithIdlingResources()
|
||||
loginRobot.assertErrorIsShown(R.string.something_went_wrong)
|
||||
.assertNotNavigatedToHome()
|
||||
.assertNotLoading()
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,99 @@
|
|||
package org.fnives.test.showcase.ui.splash
|
||||
|
||||
import androidx.arch.core.executor.testing.InstantTaskExecutorRule
|
||||
import androidx.lifecycle.Lifecycle
|
||||
import androidx.test.core.app.ActivityScenario
|
||||
import androidx.test.ext.junit.runners.AndroidJUnit4
|
||||
import dagger.hilt.android.testing.HiltAndroidRule
|
||||
import dagger.hilt.android.testing.HiltAndroidTest
|
||||
import org.fnives.test.showcase.testutils.MockServerScenarioSetupTestRule
|
||||
import org.fnives.test.showcase.testutils.configuration.SpecificTestConfigurationsFactory
|
||||
import org.fnives.test.showcase.testutils.idling.Disposable
|
||||
import org.fnives.test.showcase.testutils.idling.NetworkSynchronization
|
||||
import org.fnives.test.showcase.testutils.robot.RobotTestRule
|
||||
import org.fnives.test.showcase.testutils.statesetup.SetupLoggedInState
|
||||
import org.junit.After
|
||||
import org.junit.Before
|
||||
import org.junit.Rule
|
||||
import org.junit.Test
|
||||
import org.junit.runner.RunWith
|
||||
import org.koin.test.KoinTest
|
||||
import javax.inject.Inject
|
||||
|
||||
@Suppress("TestFunctionName")
|
||||
@RunWith(AndroidJUnit4::class)
|
||||
@HiltAndroidTest
|
||||
class SplashActivityTest : KoinTest {
|
||||
|
||||
private var activityScenario: ActivityScenario<HiltSplashActivity>? = null
|
||||
|
||||
private val splashRobot: SplashRobot get() = robotTestRule.robot
|
||||
|
||||
@Rule
|
||||
@JvmField
|
||||
val instantTaskExecutorRule = InstantTaskExecutorRule()
|
||||
|
||||
@Rule
|
||||
@JvmField
|
||||
val robotTestRule = RobotTestRule(SplashRobot())
|
||||
|
||||
@Rule
|
||||
@JvmField
|
||||
val mainDispatcherTestRule = SpecificTestConfigurationsFactory.createMainDispatcherTestRule()
|
||||
|
||||
@Rule
|
||||
@JvmField
|
||||
val mockServerScenarioSetupTestRule = MockServerScenarioSetupTestRule()
|
||||
|
||||
@Rule
|
||||
@JvmField
|
||||
val hiltRule = HiltAndroidRule(this)
|
||||
|
||||
@Inject
|
||||
lateinit var setupLoggedInState: SetupLoggedInState
|
||||
|
||||
@Inject
|
||||
lateinit var networkSynchronization: NetworkSynchronization
|
||||
|
||||
var disposable: Disposable? = null
|
||||
|
||||
@Before
|
||||
fun setUp() {
|
||||
SpecificTestConfigurationsFactory.createServerTypeConfiguration()
|
||||
.invoke(mockServerScenarioSetupTestRule.mockServerScenarioSetup)
|
||||
hiltRule.inject()
|
||||
disposable = networkSynchronization.registerNetworkingSynchronization()
|
||||
}
|
||||
|
||||
@After
|
||||
fun tearDown() {
|
||||
activityScenario?.moveToState(Lifecycle.State.DESTROYED)
|
||||
disposable?.dispose()
|
||||
}
|
||||
|
||||
@Test
|
||||
fun GIVEN_loggedInState_WHEN_opened_THEN_MainActivity_is_started() {
|
||||
setupLoggedInState.setupLogin(mockServerScenarioSetupTestRule.mockServerScenarioSetup)
|
||||
|
||||
activityScenario = ActivityScenario.launch(HiltSplashActivity::class.java)
|
||||
|
||||
mainDispatcherTestRule.advanceTimeBy(500)
|
||||
|
||||
splashRobot.assertHomeIsStarted()
|
||||
.assertAuthIsNotStarted()
|
||||
|
||||
setupLoggedInState.setupLogout()
|
||||
}
|
||||
|
||||
@Test
|
||||
fun GIVEN_loggedOffState_WHEN_opened_THEN_AuthActivity_is_started() {
|
||||
setupLoggedInState.setupLogout()
|
||||
|
||||
activityScenario = ActivityScenario.launch(HiltSplashActivity::class.java)
|
||||
|
||||
mainDispatcherTestRule.advanceTimeBy(500)
|
||||
|
||||
splashRobot.assertAuthIsStarted()
|
||||
.assertHomeIsNotStarted()
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,34 @@
|
|||
package org.fnives.test.showcase.testutils
|
||||
|
||||
import androidx.test.core.app.ApplicationProvider
|
||||
import org.fnives.test.showcase.TestShowcaseApplication
|
||||
import org.fnives.test.showcase.di.BaseUrlProvider
|
||||
import org.fnives.test.showcase.di.createAppModules
|
||||
import org.junit.rules.TestRule
|
||||
import org.junit.runner.Description
|
||||
import org.junit.runners.model.Statement
|
||||
import org.koin.android.ext.koin.androidContext
|
||||
import org.koin.core.context.GlobalContext
|
||||
import org.koin.core.context.startKoin
|
||||
import org.koin.core.context.stopKoin
|
||||
|
||||
class ReloadKoinModulesIfNecessaryTestRule : TestRule {
|
||||
override fun apply(base: Statement, description: Description): Statement =
|
||||
object : Statement() {
|
||||
override fun evaluate() {
|
||||
if (GlobalContext.getOrNull() == null) {
|
||||
val application =
|
||||
ApplicationProvider.getApplicationContext<TestShowcaseApplication>()
|
||||
startKoin {
|
||||
androidContext(application)
|
||||
modules(createAppModules(BaseUrlProvider.get()))
|
||||
}
|
||||
}
|
||||
try {
|
||||
base.evaluate()
|
||||
} finally {
|
||||
stopKoin()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,31 @@
|
|||
package org.fnives.test.showcase.testutils.statesetup
|
||||
|
||||
import kotlinx.coroutines.runBlocking
|
||||
import org.fnives.test.showcase.core.login.IsUserLoggedInUseCase
|
||||
import org.fnives.test.showcase.core.login.LoginUseCase
|
||||
import org.fnives.test.showcase.core.login.LogoutUseCase
|
||||
import org.fnives.test.showcase.model.auth.LoginCredentials
|
||||
import org.fnives.test.showcase.network.mockserver.MockServerScenarioSetup
|
||||
import org.fnives.test.showcase.network.mockserver.scenario.auth.AuthScenario
|
||||
import org.koin.test.KoinTest
|
||||
import org.koin.test.get
|
||||
|
||||
object SetupLoggedInState : KoinTest {
|
||||
|
||||
private val logoutUseCase get() = get<LogoutUseCase>()
|
||||
private val loginUseCase get() = get<LoginUseCase>()
|
||||
private val isUserLoggedInUseCase get() = get<IsUserLoggedInUseCase>()
|
||||
|
||||
fun setupLogin(mockServerScenarioSetup: MockServerScenarioSetup) {
|
||||
mockServerScenarioSetup.setScenario(AuthScenario.Success("a", "b"))
|
||||
runBlocking {
|
||||
loginUseCase.invoke(LoginCredentials("a", "b"))
|
||||
}
|
||||
}
|
||||
|
||||
fun isLoggedIn() = isUserLoggedInUseCase.invoke()
|
||||
|
||||
fun setupLogout() {
|
||||
runBlocking { logoutUseCase.invoke() }
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,14 @@
|
|||
package org.fnives.test.showcase.ui
|
||||
|
||||
import org.fnives.test.showcase.ui.auth.AuthActivity
|
||||
import org.fnives.test.showcase.ui.home.MainActivity
|
||||
import org.fnives.test.showcase.ui.splash.SplashActivity
|
||||
|
||||
object ActivityClassHolder {
|
||||
|
||||
fun authActivity() = AuthActivity::class
|
||||
|
||||
fun mainActivity() = MainActivity::class
|
||||
|
||||
fun splashActivity() = SplashActivity::class
|
||||
}
|
||||
|
|
@ -1,6 +1,7 @@
|
|||
package org.fnives.test.showcase.di
|
||||
|
||||
import android.content.Context
|
||||
import org.fnives.test.showcase.model.network.BaseUrl
|
||||
import org.fnives.test.showcase.testutils.TestMainDispatcher
|
||||
import org.fnives.test.showcase.ui.auth.AuthViewModel
|
||||
import org.fnives.test.showcase.ui.home.MainViewModel
|
||||
|
|
@ -9,8 +10,11 @@ import org.junit.jupiter.api.AfterEach
|
|||
import org.junit.jupiter.api.BeforeEach
|
||||
import org.junit.jupiter.api.Test
|
||||
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.test.KoinTest
|
||||
import org.koin.test.check.checkModules
|
||||
import org.koin.test.inject
|
||||
import org.mockito.kotlin.anyOrNull
|
||||
import org.mockito.kotlin.doReturn
|
||||
|
|
@ -38,20 +42,20 @@ class DITest : KoinTest {
|
|||
fun verifyStaticModules() {
|
||||
val mockContext = mock<Context>()
|
||||
whenever(mockContext.getSharedPreferences(anyOrNull(), anyOrNull())).doReturn(mock())
|
||||
// checkModules {
|
||||
// androidContext(mockContext)
|
||||
// modules(createAppModules(BaseUrl("https://a.com/")))
|
||||
// }
|
||||
checkModules {
|
||||
androidContext(mockContext)
|
||||
modules(createAppModules(BaseUrl("https://a.com/")))
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun verifyViewModelModules() {
|
||||
val mockContext = mock<Context>()
|
||||
whenever(mockContext.getSharedPreferences(anyOrNull(), anyOrNull())).doReturn(mock())
|
||||
// startKoin {
|
||||
// androidContext(mockContext)
|
||||
// modules(createAppModules(BaseUrl("https://a.com/")))
|
||||
// }
|
||||
startKoin {
|
||||
androidContext(mockContext)
|
||||
modules(createAppModules(BaseUrl("https://a.com/")))
|
||||
}
|
||||
authViewModel
|
||||
mainViewModel
|
||||
splashViewModel
|
||||
|
|
@ -45,7 +45,7 @@ task unitTests(dependsOn: ["app:testKoinDebugUnitTest", "app:testHiltDebugUnitTe
|
|||
description = 'Run all unit tests'
|
||||
}
|
||||
|
||||
task androidTests(dependsOn: "app:connectedAndroidTest"){
|
||||
task androidTests(dependsOn: ["app:connectedKoinDebugAndroidTest", "app:connectedHiltDebugAndroidTest"]){
|
||||
group = 'Tests'
|
||||
description = 'Run all Android tests'
|
||||
}
|
||||
|
|
|
|||
|
|
@ -6,11 +6,12 @@ import org.fnives.test.showcase.core.di.hilt.CoreModule
|
|||
import org.fnives.test.showcase.core.di.hilt.ReloadLoggedInModuleInjectModuleImpl
|
||||
import org.fnives.test.showcase.core.session.SessionExpirationListener
|
||||
import org.fnives.test.showcase.core.storage.UserDataLocalStorage
|
||||
import org.fnives.test.showcase.network.di.hilt.BindsBaseOkHttpClient
|
||||
import org.fnives.test.showcase.network.di.hilt.HiltNetworkModule
|
||||
import javax.inject.Singleton
|
||||
|
||||
@Singleton
|
||||
@Component(modules = [CoreModule::class, HiltNetworkModule::class, ReloadLoggedInModuleInjectModuleImpl::class])
|
||||
@Component(modules = [CoreModule::class, HiltNetworkModule::class, ReloadLoggedInModuleInjectModuleImpl::class, BindsBaseOkHttpClient::class])
|
||||
internal interface TestCoreComponent {
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -6,4 +6,8 @@ plugins {
|
|||
java {
|
||||
sourceCompatibility = JavaVersion.VERSION_1_8
|
||||
targetCompatibility = JavaVersion.VERSION_1_8
|
||||
}
|
||||
|
||||
dependencies {
|
||||
implementation "javax.inject:javax.inject:1"
|
||||
}
|
||||
|
|
@ -1,4 +1,4 @@
|
|||
package org.fnives.test.showcase.network.di.hilt
|
||||
package org.fnives.test.showcase.hilt
|
||||
|
||||
import javax.inject.Qualifier
|
||||
|
||||
|
|
@ -1,4 +1,4 @@
|
|||
package org.fnives.test.showcase.network.di.hilt
|
||||
package org.fnives.test.showcase.hilt
|
||||
|
||||
import javax.inject.Qualifier
|
||||
|
||||
|
|
@ -17,9 +17,12 @@ dependencies {
|
|||
implementation "com.squareup.moshi:moshi:$moshi_version"
|
||||
kapt "com.squareup.moshi:moshi-kotlin-codegen:$moshi_version"
|
||||
implementation "com.squareup.okhttp3:logging-interceptor:$okhttp_version"
|
||||
|
||||
// koin
|
||||
api "io.insert-koin:koin-core:$koin_version"
|
||||
|
||||
// hilt
|
||||
implementation "com.google.dagger:hilt-core:$hilt_version"
|
||||
kapt "com.google.dagger:hilt-compiler:$hilt_version"
|
||||
|
||||
api project(":model")
|
||||
|
||||
|
|
@ -30,5 +33,6 @@ dependencies {
|
|||
testImplementation "io.insert-koin:koin-test-junit5:$koin_version"
|
||||
testImplementation "org.skyscreamer:jsonassert:$testing_json_assert_version"
|
||||
testRuntimeOnly "org.junit.jupiter:junit-jupiter-engine:$testing_junit5_version"
|
||||
kapt "com.google.dagger:hilt-compiler:$hilt_version"
|
||||
kaptTest "com.google.dagger:dagger-compiler:$hilt_version"
|
||||
}
|
||||
|
|
@ -0,0 +1,17 @@
|
|||
package org.fnives.test.showcase.network.di.hilt
|
||||
|
||||
import dagger.Binds
|
||||
import dagger.Module
|
||||
import dagger.hilt.InstallIn
|
||||
import dagger.hilt.components.SingletonComponent
|
||||
import okhttp3.OkHttpClient
|
||||
import org.fnives.test.showcase.hilt.SessionLessQualifier
|
||||
|
||||
@InstallIn(SingletonComponent::class)
|
||||
@Module
|
||||
abstract class BindsBaseOkHttpClient {
|
||||
|
||||
@Binds
|
||||
@SessionLessQualifier
|
||||
abstract fun bindsSessionLess(okHttpClient: OkHttpClient) : OkHttpClient
|
||||
}
|
||||
|
|
@ -5,6 +5,8 @@ import dagger.Provides
|
|||
import dagger.hilt.InstallIn
|
||||
import dagger.hilt.components.SingletonComponent
|
||||
import okhttp3.OkHttpClient
|
||||
import org.fnives.test.showcase.hilt.SessionLessQualifier
|
||||
import org.fnives.test.showcase.hilt.SessionQualifier
|
||||
import org.fnives.test.showcase.network.auth.LoginRemoteSource
|
||||
import org.fnives.test.showcase.network.auth.LoginRemoteSourceImpl
|
||||
import org.fnives.test.showcase.network.auth.LoginService
|
||||
|
|
@ -31,7 +33,6 @@ object HiltNetworkModule {
|
|||
|
||||
@Provides
|
||||
@Singleton
|
||||
@SessionLessQualifier
|
||||
fun provideSessionLessOkHttpClient(enableLogging: Boolean) =
|
||||
OkHttpClient.Builder()
|
||||
.addInterceptor(PlatformInterceptor())
|
||||
|
|
|
|||
|
|
@ -6,13 +6,14 @@ import org.fnives.test.showcase.network.auth.hilt.LoginRemoteSourceRefreshAction
|
|||
import org.fnives.test.showcase.network.auth.hilt.LoginRemoteSourceTest
|
||||
import org.fnives.test.showcase.network.content.hilt.ContentRemoteSourceImplTest
|
||||
import org.fnives.test.showcase.network.content.hilt.SessionExpirationTest
|
||||
import org.fnives.test.showcase.network.di.hilt.BindsBaseOkHttpClient
|
||||
import org.fnives.test.showcase.network.di.hilt.HiltNetworkModule
|
||||
import org.fnives.test.showcase.network.session.NetworkSessionExpirationListener
|
||||
import org.fnives.test.showcase.network.session.NetworkSessionLocalStorage
|
||||
import javax.inject.Singleton
|
||||
|
||||
@Singleton
|
||||
@Component(modules = [HiltNetworkModule::class])
|
||||
@Component(modules = [HiltNetworkModule::class, BindsBaseOkHttpClient::class])
|
||||
interface TestNetworkComponent {
|
||||
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue