diff --git a/app/src/sharedTest/java/org/fnives/test/showcase/testutils/MockServerScenarioSetupTestRule.kt b/app/src/sharedTest/java/org/fnives/test/showcase/testutils/MockServerScenarioSetupResetingTestRule.kt similarity index 69% rename from app/src/sharedTest/java/org/fnives/test/showcase/testutils/MockServerScenarioSetupTestRule.kt rename to app/src/sharedTest/java/org/fnives/test/showcase/testutils/MockServerScenarioSetupResetingTestRule.kt index 36755f0..cd1c405 100644 --- a/app/src/sharedTest/java/org/fnives/test/showcase/testutils/MockServerScenarioSetupTestRule.kt +++ b/app/src/sharedTest/java/org/fnives/test/showcase/testutils/MockServerScenarioSetupResetingTestRule.kt @@ -4,7 +4,9 @@ import okhttp3.OkHttpClient import okhttp3.tls.HandshakeCertificates import org.fnives.test.showcase.model.network.BaseUrl import org.fnives.test.showcase.network.mockserver.MockServerScenarioSetup -import org.fnives.test.showcase.testutils.idling.NetworkSynchronization.OkHttpClientTypes +import org.fnives.test.showcase.testutils.idling.NetworkSynchronizationTestRule +import org.fnives.test.showcase.testutils.idling.NetworkSynchronizationTestRule.OkHttpClientTypes +import org.junit.rules.TestRule import org.junit.runner.Description import org.junit.runners.model.Statement import org.koin.core.context.loadKoinModules @@ -12,14 +14,26 @@ import org.koin.dsl.module import org.koin.test.KoinTest import org.koin.test.get -class MockServerScenarioSetupTestRule : ReloadKoinModulesIfNecessaryTestRule(), KoinTest { +/** + * TestRule which ensures Koin is reseted between each tests and setups Network mocking. + * + * It First resets koin if needed. + * Then creates and starts the mockwebserver, it also injects the correct baseUrl into the OkHttp Client. + * Then synchronizes Espresso with the OkHttp Client + */ +class MockServerScenarioSetupResetingTestRule( + private val reloadKoinModulesIfNecessaryTestRule: ReloadKoinModulesIfNecessaryTestRule = ReloadKoinModulesIfNecessaryTestRule(), + private val networkSynchronizationTestRule: NetworkSynchronizationTestRule = NetworkSynchronizationTestRule() +) : TestRule, KoinTest { lateinit var mockServerScenarioSetup: MockServerScenarioSetup private val sessionlessQualifier get() = OkHttpClientTypes.SESSIONLESS.asQualifier() override fun apply(base: Statement, description: Description): Statement = - super.apply(createStatement(base), description) + networkSynchronizationTestRule.apply(base, description) + .let(::createStatement) + .let { reloadKoinModulesIfNecessaryTestRule.apply(it, description) } private fun createStatement(base: Statement) = object : Statement() { @Throws(Throwable::class) diff --git a/app/src/sharedTest/java/org/fnives/test/showcase/testutils/ReloadKoinModulesIfNecessaryTestRule.kt b/app/src/sharedTest/java/org/fnives/test/showcase/testutils/ReloadKoinModulesIfNecessaryTestRule.kt index e241826..ec0a5b5 100644 --- a/app/src/sharedTest/java/org/fnives/test/showcase/testutils/ReloadKoinModulesIfNecessaryTestRule.kt +++ b/app/src/sharedTest/java/org/fnives/test/showcase/testutils/ReloadKoinModulesIfNecessaryTestRule.kt @@ -9,6 +9,7 @@ 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 import org.koin.mp.KoinPlatformTools @@ -22,7 +23,7 @@ import org.koin.test.KoinTest * * Note: Do not use if you want your test's to share Koin, and in such case do not stop your Koin. */ -open class ReloadKoinModulesIfNecessaryTestRule : TestRule, KoinTest { +class ReloadKoinModulesIfNecessaryTestRule : TestRule, KoinTest { override fun apply(base: Statement, description: Description): Statement = ReinitKoinStatement(base) @@ -38,6 +39,7 @@ open class ReloadKoinModulesIfNecessaryTestRule : TestRule, KoinTest { private fun reinitKoinIfNeeded() { if (KoinPlatformTools.defaultContext().getOrNull() != null) return + if (GlobalContext.getOrNull() != null) return val application = ApplicationProvider.getApplicationContext() val baseUrl = BaseUrl(BuildConfig.BASE_URL) diff --git a/app/src/sharedTest/java/org/fnives/test/showcase/testutils/configuration/MainDispatcherTestRule.kt b/app/src/sharedTest/java/org/fnives/test/showcase/testutils/configuration/MainDispatcherTestRule.kt index 6104117..817617a 100644 --- a/app/src/sharedTest/java/org/fnives/test/showcase/testutils/configuration/MainDispatcherTestRule.kt +++ b/app/src/sharedTest/java/org/fnives/test/showcase/testutils/configuration/MainDispatcherTestRule.kt @@ -12,3 +12,7 @@ interface MainDispatcherTestRule : TestRule { fun advanceTimeBy(delayInMillis: Long) } + +@Suppress("TestFunctionName") +fun MainDispatcherTestRule(): MainDispatcherTestRule = + SpecificTestConfigurationsFactory.createMainDispatcherTestRule() diff --git a/app/src/sharedTest/java/org/fnives/test/showcase/testutils/idling/NetworkSynchronization.kt b/app/src/sharedTest/java/org/fnives/test/showcase/testutils/idling/NetworkSynchronizationTestRule.kt similarity index 59% rename from app/src/sharedTest/java/org/fnives/test/showcase/testutils/idling/NetworkSynchronization.kt rename to app/src/sharedTest/java/org/fnives/test/showcase/testutils/idling/NetworkSynchronizationTestRule.kt index 135dce1..80c5795 100644 --- a/app/src/sharedTest/java/org/fnives/test/showcase/testutils/idling/NetworkSynchronization.kt +++ b/app/src/sharedTest/java/org/fnives/test/showcase/testutils/idling/NetworkSynchronizationTestRule.kt @@ -3,14 +3,35 @@ package org.fnives.test.showcase.testutils.idling import androidx.annotation.CheckResult import androidx.test.espresso.IdlingResource import okhttp3.OkHttpClient +import org.junit.rules.TestRule +import org.junit.runner.Description +import org.junit.runners.model.Statement import org.koin.core.qualifier.StringQualifier import org.koin.test.KoinTest import org.koin.test.get -object NetworkSynchronization : KoinTest { +class NetworkSynchronizationTestRule : TestRule, KoinTest { + + private var disposable: Disposable? = null + + override fun apply(base: Statement, description: Description): Statement { + return object : Statement() { + override fun evaluate() { + disposable = registerNetworkingSynchronization() + try { + base.evaluate() + } finally { + dispose() + } + } + + } + } + + fun dispose() = disposable?.dispose() @CheckResult - fun registerNetworkingSynchronization(): Disposable { + private fun registerNetworkingSynchronization(): Disposable { val idlingResources = OkHttpClientTypes.values() .map { it to getOkHttpClient(it) } .associateBy { it.second.dispatcher } diff --git a/app/src/sharedTest/java/org/fnives/test/showcase/testutils/statesetup/SetupAuthenticationState.kt b/app/src/sharedTest/java/org/fnives/test/showcase/testutils/statesetup/SetupAuthenticationState.kt index febf535..ad90612 100644 --- a/app/src/sharedTest/java/org/fnives/test/showcase/testutils/statesetup/SetupAuthenticationState.kt +++ b/app/src/sharedTest/java/org/fnives/test/showcase/testutils/statesetup/SetupAuthenticationState.kt @@ -2,6 +2,8 @@ package org.fnives.test.showcase.testutils.statesetup import androidx.lifecycle.Lifecycle import androidx.test.core.app.ActivityScenario +import androidx.test.espresso.intent.Intents +import androidx.test.runner.intent.IntentStubberRegistry import org.fnives.test.showcase.network.mockserver.MockServerScenarioSetup import org.fnives.test.showcase.network.mockserver.scenario.auth.AuthScenario import org.fnives.test.showcase.testutils.configuration.MainDispatcherTestRule @@ -15,7 +17,8 @@ object SetupAuthenticationState : KoinTest { fun setupLogin( mainDispatcherTestRule: MainDispatcherTestRule, - mockServerScenarioSetup: MockServerScenarioSetup + mockServerScenarioSetup: MockServerScenarioSetup, + resetIntents: Boolean = true ) { mockServerScenarioSetup.setScenario(AuthScenario.Success(username = "a", password = "b")) val activityScenario = ActivityScenario.launch(AuthActivity::class.java) @@ -30,19 +33,27 @@ object SetupAuthenticationState : KoinTest { mainDispatcherTestRule.advanceUntilIdleOrActivityIsDestroyed() activityScenario.close() + resetIntentsIfNeeded(resetIntents) } fun setupLogout( - mainDispatcherTestRule: MainDispatcherTestRule + mainDispatcherTestRule: MainDispatcherTestRule, + resetIntents: Boolean = true ) { val activityScenario = ActivityScenario.launch(MainActivity::class.java) activityScenario.moveToState(Lifecycle.State.RESUMED) - val homeRobot = HomeRobot() - homeRobot - .clickSignOut() + HomeRobot().clickSignOut() mainDispatcherTestRule.advanceUntilIdleOrActivityIsDestroyed() activityScenario.close() + resetIntentsIfNeeded(resetIntents) + } + + private fun resetIntentsIfNeeded(resetIntents: Boolean) { + if (resetIntents && IntentStubberRegistry.isLoaded()) { + Intents.release() + Intents.init() + } } } diff --git a/app/src/sharedTest/java/org/fnives/test/showcase/ui/home/HomeRobot.kt b/app/src/sharedTest/java/org/fnives/test/showcase/ui/home/HomeRobot.kt index c13ef6b..c0a74fc 100644 --- a/app/src/sharedTest/java/org/fnives/test/showcase/ui/home/HomeRobot.kt +++ b/app/src/sharedTest/java/org/fnives/test/showcase/ui/home/HomeRobot.kt @@ -19,10 +19,7 @@ import androidx.test.espresso.matcher.ViewMatchers.withText import org.fnives.test.showcase.R import org.fnives.test.showcase.model.content.Content import org.fnives.test.showcase.model.content.FavouriteContent -import org.fnives.test.showcase.network.mockserver.MockServerScenarioSetup -import org.fnives.test.showcase.testutils.configuration.MainDispatcherTestRule import org.fnives.test.showcase.testutils.robot.Robot -import org.fnives.test.showcase.testutils.statesetup.SetupAuthenticationState import org.fnives.test.showcase.testutils.viewactions.PullToRefresh import org.fnives.test.showcase.testutils.viewactions.WithDrawable import org.fnives.test.showcase.testutils.viewactions.notIntended @@ -33,8 +30,6 @@ class HomeRobot : Robot { override fun init() { Intents.init() - Intents.intending(IntentMatchers.hasComponent(AuthActivity::class.java.canonicalName)) - .respondWith(Instrumentation.ActivityResult(0, null)) } override fun release() { @@ -50,6 +45,9 @@ class HomeRobot : Robot { } fun clickSignOut() = apply { + Intents.intending(IntentMatchers.hasComponent(AuthActivity::class.java.canonicalName)) + .respondWith(Instrumentation.ActivityResult(0, null)) + Espresso.onView(withId(R.id.logout_cta)).perform(click()) } @@ -103,11 +101,4 @@ class HomeRobot : Robot { Espresso.onView(withId(R.id.error_message)) .check(matches(allOf(isDisplayed(), withText(R.string.something_went_wrong)))) } - - fun setupLogin( - mainDispatcherTestRule: MainDispatcherTestRule, - mockServerScenarioSetup: MockServerScenarioSetup - ) { - SetupAuthenticationState.setupLogin(mainDispatcherTestRule, mockServerScenarioSetup) - } } diff --git a/app/src/sharedTest/java/org/fnives/test/showcase/ui/home/MainActivityTest.kt b/app/src/sharedTest/java/org/fnives/test/showcase/ui/home/MainActivityTest.kt index 269d9c5..d8273df 100644 --- a/app/src/sharedTest/java/org/fnives/test/showcase/ui/home/MainActivityTest.kt +++ b/app/src/sharedTest/java/org/fnives/test/showcase/ui/home/MainActivityTest.kt @@ -6,17 +6,17 @@ 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.MockServerScenarioSetupResetingTestRule +import org.fnives.test.showcase.testutils.configuration.MainDispatcherTestRule 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.SetupAuthenticationState.setupLogin import org.junit.After import org.junit.Before import org.junit.Rule import org.junit.Test +import org.junit.rules.RuleChain import org.junit.runner.RunWith import org.koin.test.KoinTest @@ -26,37 +26,26 @@ class MainActivityTest : KoinTest { private lateinit var activityScenario: ActivityScenario - @Rule - @JvmField - val robotRule = RobotTestRule(HomeRobot()) - private val homeRobot get() = robotRule.robot + private val mockServerScenarioSetupTestRule = MockServerScenarioSetupResetingTestRule() + private val mockServerScenarioSetup + get() = mockServerScenarioSetupTestRule.mockServerScenarioSetup + private val mainDispatcherTestRule = MainDispatcherTestRule() + private val robot = HomeRobot() @Rule @JvmField - val mockServerScenarioSetupTestRule = MockServerScenarioSetupTestRule() - - val mockServerScenarioSetup get() = mockServerScenarioSetupTestRule.mockServerScenarioSetup - - @Rule - @JvmField - val mainDispatcherTestRule = SpecificTestConfigurationsFactory.createMainDispatcherTestRule() - - private lateinit var disposable: Disposable + val ruleOrder: RuleChain = RuleChain.outerRule(mockServerScenarioSetupTestRule) + .around(mainDispatcherTestRule) + .around(RobotTestRule(robot)) @Before - fun setUp() { - - disposable = NetworkSynchronization.registerNetworkingSynchronization() - homeRobot.setupLogin( - mainDispatcherTestRule, - mockServerScenarioSetup - ) + fun setup() { + setupLogin(mainDispatcherTestRule, mockServerScenarioSetup) } @After fun tearDown() { activityScenario.close() - disposable.dispose() } /** GIVEN initialized MainActivity WHEN signout is clicked THEN user is signed out */ @@ -66,10 +55,10 @@ class MainActivityTest : KoinTest { activityScenario = ActivityScenario.launch(MainActivity::class.java) mainDispatcherTestRule.advanceUntilIdleWithIdlingResources() - homeRobot.clickSignOut() + robot.clickSignOut() mainDispatcherTestRule.advanceUntilIdleOrActivityIsDestroyed() - homeRobot.assertNavigatedToAuth() + robot.assertNavigatedToAuth() } /** GIVEN success response WHEN data is returned THEN it is shown on the ui */ @@ -80,9 +69,9 @@ class MainActivityTest : KoinTest { mainDispatcherTestRule.advanceUntilIdleWithIdlingResources() ContentData.contentSuccess.forEachIndexed { index, content -> - homeRobot.assertContainsItem(index, FavouriteContent(content, false)) + robot.assertContainsItem(index, FavouriteContent(content, false)) } - homeRobot.assertDidNotNavigateToAuth() + robot.assertDidNotNavigateToAuth() } /** GIVEN success response WHEN item is clicked THEN ui is updated */ @@ -92,11 +81,11 @@ class MainActivityTest : KoinTest { activityScenario = ActivityScenario.launch(MainActivity::class.java) mainDispatcherTestRule.advanceUntilIdleWithIdlingResources() - homeRobot.clickOnContentItem(0, ContentData.contentSuccess.first()) + robot.clickOnContentItem(0, ContentData.contentSuccess.first()) mainDispatcherTestRule.advanceUntilIdleWithIdlingResources() val expectedItem = FavouriteContent(ContentData.contentSuccess.first(), true) - homeRobot.assertContainsItem(0, expectedItem) + robot.assertContainsItem(0, expectedItem) .assertDidNotNavigateToAuth() } @@ -107,7 +96,7 @@ class MainActivityTest : KoinTest { activityScenario = ActivityScenario.launch(MainActivity::class.java) mainDispatcherTestRule.advanceUntilIdleWithIdlingResources() - homeRobot.clickOnContentItem(0, ContentData.contentSuccess.first()) + robot.clickOnContentItem(0, ContentData.contentSuccess.first()) mainDispatcherTestRule.advanceUntilIdleWithIdlingResources() val expectedItem = FavouriteContent(ContentData.contentSuccess.first(), true) @@ -116,7 +105,7 @@ class MainActivityTest : KoinTest { activityScenario = ActivityScenario.launch(MainActivity::class.java) mainDispatcherTestRule.advanceUntilIdleWithIdlingResources() - homeRobot.assertContainsItem(0, expectedItem) + robot.assertContainsItem(0, expectedItem) .assertDidNotNavigateToAuth() } @@ -127,13 +116,13 @@ class MainActivityTest : KoinTest { activityScenario = ActivityScenario.launch(MainActivity::class.java) mainDispatcherTestRule.advanceUntilIdleWithIdlingResources() - homeRobot.clickOnContentItem(0, ContentData.contentSuccess.first()) + robot.clickOnContentItem(0, ContentData.contentSuccess.first()) mainDispatcherTestRule.advanceUntilIdleWithIdlingResources() - homeRobot.clickOnContentItem(0, ContentData.contentSuccess.first()) + robot.clickOnContentItem(0, ContentData.contentSuccess.first()) mainDispatcherTestRule.advanceUntilIdleWithIdlingResources() val expectedItem = FavouriteContent(ContentData.contentSuccess.first(), false) - homeRobot.assertContainsItem(0, expectedItem) + robot.assertContainsItem(0, expectedItem) .assertDidNotNavigateToAuth() } @@ -144,7 +133,7 @@ class MainActivityTest : KoinTest { activityScenario = ActivityScenario.launch(MainActivity::class.java) mainDispatcherTestRule.advanceUntilIdleWithIdlingResources() - homeRobot.assertContainsNoItems() + robot.assertContainsNoItems() .assertContainsError() .assertDidNotNavigateToAuth() } @@ -159,14 +148,14 @@ class MainActivityTest : KoinTest { activityScenario = ActivityScenario.launch(MainActivity::class.java) mainDispatcherTestRule.advanceUntilIdleWithIdlingResources() - homeRobot.swipeRefresh() + robot.swipeRefresh() mainDispatcherTestRule.advanceUntilIdleWithIdlingResources() loopMainThreadFor(2000L) ContentData.contentSuccess.forEachIndexed { index, content -> - homeRobot.assertContainsItem(index, FavouriteContent(content, false)) + robot.assertContainsItem(index, FavouriteContent(content, false)) } - homeRobot.assertDidNotNavigateToAuth() + robot.assertDidNotNavigateToAuth() } /** GIVEN success then error WHEN retried THEN error is shown */ @@ -179,13 +168,13 @@ class MainActivityTest : KoinTest { activityScenario = ActivityScenario.launch(MainActivity::class.java) mainDispatcherTestRule.advanceUntilIdleWithIdlingResources() - homeRobot.swipeRefresh() + robot.swipeRefresh() mainDispatcherTestRule.advanceUntilIdleWithIdlingResources() loopMainThreadUntilIdleWithIdlingResources() mainDispatcherTestRule.advanceTimeBy(1000L) loopMainThreadFor(1000) - homeRobot + robot .assertContainsError() .assertContainsNoItems() .assertDidNotNavigateToAuth() @@ -204,9 +193,9 @@ class MainActivityTest : KoinTest { mainDispatcherTestRule.advanceUntilIdleWithIdlingResources() ContentData.contentSuccess.forEachIndexed { index, content -> - homeRobot.assertContainsItem(index, FavouriteContent(content, false)) + robot.assertContainsItem(index, FavouriteContent(content, false)) } - homeRobot.assertDidNotNavigateToAuth() + robot.assertDidNotNavigateToAuth() } /** GIVEN unauthenticated then error WHEN loaded THEN navigated to auth */ @@ -218,6 +207,6 @@ class MainActivityTest : KoinTest { activityScenario = ActivityScenario.launch(MainActivity::class.java) mainDispatcherTestRule.advanceUntilIdleWithIdlingResources() - homeRobot.assertNavigatedToAuth() + robot.assertNavigatedToAuth() } } diff --git a/app/src/sharedTest/java/org/fnives/test/showcase/ui/login/AuthActivityTest.kt b/app/src/sharedTest/java/org/fnives/test/showcase/ui/login/AuthActivityTest.kt index 26656c6..f167a58 100644 --- a/app/src/sharedTest/java/org/fnives/test/showcase/ui/login/AuthActivityTest.kt +++ b/app/src/sharedTest/java/org/fnives/test/showcase/ui/login/AuthActivityTest.kt @@ -4,16 +4,14 @@ import androidx.test.core.app.ActivityScenario import androidx.test.ext.junit.runners.AndroidJUnit4 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.MockServerScenarioSetupResetingTestRule +import org.fnives.test.showcase.testutils.configuration.MainDispatcherTestRule import org.fnives.test.showcase.testutils.robot.RobotTestRule import org.fnives.test.showcase.ui.auth.AuthActivity import org.junit.After -import org.junit.Before import org.junit.Rule import org.junit.Test +import org.junit.rules.RuleChain import org.junit.runner.RunWith import org.koin.test.KoinTest @@ -23,31 +21,20 @@ class AuthActivityTest : KoinTest { private lateinit var activityScenario: ActivityScenario - @Rule - @JvmField - val robotRule = RobotTestRule(LoginRobot()) - private val loginRobot get() = robotRule.robot + private val mockServerScenarioSetupTestRule = MockServerScenarioSetupResetingTestRule() + private val mockServerScenarioSetup get() = mockServerScenarioSetupTestRule.mockServerScenarioSetup + private val mainDispatcherTestRule = MainDispatcherTestRule() + private val robot = LoginRobot() @Rule @JvmField - val mockServerScenarioSetupTestRule = MockServerScenarioSetupTestRule() - val mockServerScenarioSetup get() = mockServerScenarioSetupTestRule.mockServerScenarioSetup - - @Rule - @JvmField - val mainDispatcherTestRule = SpecificTestConfigurationsFactory.createMainDispatcherTestRule() - - private lateinit var disposable: Disposable - - @Before - fun setUp() { - disposable = NetworkSynchronization.registerNetworkingSynchronization() - } + val ruleOrder: RuleChain = RuleChain.outerRule(mockServerScenarioSetupTestRule) + .around(mainDispatcherTestRule) + .around(RobotTestRule(robot)) @After fun tearDown() { activityScenario.close() - disposable.dispose() } /** GIVEN non empty password and username and successful response WHEN signIn THEN no error is shown and navigating to home */ @@ -57,7 +44,7 @@ class AuthActivityTest : KoinTest { AuthScenario.Success(password = "alma", username = "banan") ) activityScenario = ActivityScenario.launch(AuthActivity::class.java) - loginRobot + robot .setPassword("alma") .setUsername("banan") .assertPassword("alma") @@ -66,21 +53,21 @@ class AuthActivityTest : KoinTest { .assertLoadingBeforeRequests() mainDispatcherTestRule.advanceUntilIdleOrActivityIsDestroyed() - loginRobot.assertNavigatedToHome() + robot.assertNavigatedToHome() } /** GIVEN empty password and username WHEN signIn THEN error password is shown */ @Test fun emptyPasswordShowsProperErrorMessage() { activityScenario = ActivityScenario.launch(AuthActivity::class.java) - loginRobot + robot .setUsername("banan") .assertUsername("banan") .clickOnLogin() .assertLoadingBeforeRequests() mainDispatcherTestRule.advanceUntilIdleWithIdlingResources() - loginRobot.assertErrorIsShown(R.string.password_is_invalid) + robot.assertErrorIsShown(R.string.password_is_invalid) .assertNotNavigatedToHome() .assertNotLoading() } @@ -89,14 +76,14 @@ class AuthActivityTest : KoinTest { @Test fun emptyUserNameShowsProperErrorMessage() { activityScenario = ActivityScenario.launch(AuthActivity::class.java) - loginRobot + robot .setPassword("banan") .assertPassword("banan") .clickOnLogin() .assertLoadingBeforeRequests() mainDispatcherTestRule.advanceUntilIdleWithIdlingResources() - loginRobot.assertErrorIsShown(R.string.username_is_invalid) + robot.assertErrorIsShown(R.string.username_is_invalid) .assertNotNavigatedToHome() .assertNotLoading() } @@ -108,7 +95,7 @@ class AuthActivityTest : KoinTest { AuthScenario.InvalidCredentials(username = "alma", password = "banan") ) activityScenario = ActivityScenario.launch(AuthActivity::class.java) - loginRobot + robot .setUsername("alma") .setPassword("banan") .assertUsername("alma") @@ -117,7 +104,7 @@ class AuthActivityTest : KoinTest { .assertLoadingBeforeRequests() mainDispatcherTestRule.advanceUntilIdleWithIdlingResources() - loginRobot.assertErrorIsShown(R.string.credentials_invalid) + robot.assertErrorIsShown(R.string.credentials_invalid) .assertNotNavigatedToHome() .assertNotLoading() } @@ -129,7 +116,7 @@ class AuthActivityTest : KoinTest { AuthScenario.GenericError(username = "alma", password = "banan") ) activityScenario = ActivityScenario.launch(AuthActivity::class.java) - loginRobot + robot .setUsername("alma") .setPassword("banan") .assertUsername("alma") @@ -138,7 +125,7 @@ class AuthActivityTest : KoinTest { .assertLoadingBeforeRequests() mainDispatcherTestRule.advanceUntilIdleWithIdlingResources() - loginRobot.assertErrorIsShown(R.string.something_went_wrong) + robot.assertErrorIsShown(R.string.something_went_wrong) .assertNotNavigatedToHome() .assertNotLoading() } diff --git a/app/src/sharedTest/java/org/fnives/test/showcase/ui/splash/SplashActivityTest.kt b/app/src/sharedTest/java/org/fnives/test/showcase/ui/splash/SplashActivityTest.kt index 71fabde..2e9fc7b 100644 --- a/app/src/sharedTest/java/org/fnives/test/showcase/ui/splash/SplashActivityTest.kt +++ b/app/src/sharedTest/java/org/fnives/test/showcase/ui/splash/SplashActivityTest.kt @@ -3,15 +3,15 @@ package org.fnives.test.showcase.ui.splash import androidx.lifecycle.Lifecycle import androidx.test.core.app.ActivityScenario import androidx.test.ext.junit.runners.AndroidJUnit4 -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.MockServerScenarioSetupResetingTestRule +import org.fnives.test.showcase.testutils.configuration.MainDispatcherTestRule import org.fnives.test.showcase.testutils.robot.RobotTestRule +import org.fnives.test.showcase.testutils.statesetup.SetupAuthenticationState.setupLogin +import org.fnives.test.showcase.testutils.statesetup.SetupAuthenticationState.setupLogout import org.junit.After -import org.junit.Before import org.junit.Rule import org.junit.Test +import org.junit.rules.RuleChain import org.junit.runner.RunWith import org.koin.test.KoinTest @@ -21,44 +21,33 @@ class SplashActivityTest : KoinTest { private lateinit var activityScenario: ActivityScenario - private val splashRobot: SplashRobot get() = robotTestRule.robot + private val mainDispatcherTestRule = MainDispatcherTestRule() + private val mockServerScenarioSetupTestRule = MockServerScenarioSetupResetingTestRule() + + private val robot = SplashRobot() @Rule @JvmField - val robotTestRule = RobotTestRule(SplashRobot()) - - @Rule - @JvmField - val mainDispatcherTestRule = SpecificTestConfigurationsFactory.createMainDispatcherTestRule() - - @Rule - @JvmField - val mockServerScenarioSetupTestRule = MockServerScenarioSetupTestRule() - - lateinit var disposable: Disposable - - @Before - fun setUp() { - disposable = NetworkSynchronization.registerNetworkingSynchronization() - } + val ruleOrder: RuleChain = RuleChain.outerRule(mockServerScenarioSetupTestRule) + .around(mainDispatcherTestRule) + .around(RobotTestRule(robot)) @After fun tearDown() { activityScenario.close() - disposable.dispose() } /** GIVEN loggedInState WHEN opened after some time THEN MainActivity is started */ @Test fun loggedInStateNavigatesToHome() { - splashRobot.setupLoggedInState(mainDispatcherTestRule, mockServerScenarioSetupTestRule.mockServerScenarioSetup) + setupLogin(mainDispatcherTestRule, mockServerScenarioSetupTestRule.mockServerScenarioSetup) activityScenario = ActivityScenario.launch(SplashActivity::class.java) activityScenario.moveToState(Lifecycle.State.RESUMED) mainDispatcherTestRule.advanceTimeBy(501) - splashRobot.assertHomeIsStarted() + robot.assertHomeIsStarted() .assertAuthIsNotStarted() workaroundForActivityScenarioCLoseLockingUp() @@ -67,13 +56,13 @@ class SplashActivityTest : KoinTest { /** GIVEN loggedOffState WHEN opened after some time THEN AuthActivity is started */ @Test fun loggedOutStatesNavigatesToAuthentication() { - splashRobot.setupLoggedOutState(mainDispatcherTestRule) + setupLogout(mainDispatcherTestRule) activityScenario = ActivityScenario.launch(SplashActivity::class.java) activityScenario.moveToState(Lifecycle.State.RESUMED) mainDispatcherTestRule.advanceTimeBy(501) - splashRobot.assertAuthIsStarted() + robot.assertAuthIsStarted() .assertHomeIsNotStarted() workaroundForActivityScenarioCLoseLockingUp() @@ -82,27 +71,27 @@ class SplashActivityTest : KoinTest { /** GIVEN loggedOffState and not enough time WHEN opened THEN no activity is started */ @Test fun loggedOutStatesNotEnoughTime() { - splashRobot.setupLoggedOutState(mainDispatcherTestRule) + setupLogout(mainDispatcherTestRule) activityScenario = ActivityScenario.launch(SplashActivity::class.java) activityScenario.moveToState(Lifecycle.State.RESUMED) mainDispatcherTestRule.advanceTimeBy(10) - splashRobot.assertAuthIsNotStarted() + robot.assertAuthIsNotStarted() .assertHomeIsNotStarted() } /** GIVEN loggedInState and not enough time WHEN opened THEN no activity is started */ @Test fun loggedInStatesNotEnoughTime() { - splashRobot.setupLoggedInState(mainDispatcherTestRule, mockServerScenarioSetupTestRule.mockServerScenarioSetup) + setupLogin(mainDispatcherTestRule, mockServerScenarioSetupTestRule.mockServerScenarioSetup) activityScenario = ActivityScenario.launch(SplashActivity::class.java) activityScenario.moveToState(Lifecycle.State.RESUMED) mainDispatcherTestRule.advanceTimeBy(10) - splashRobot.assertHomeIsNotStarted() + robot.assertHomeIsNotStarted() .assertAuthIsNotStarted() } diff --git a/app/src/sharedTest/java/org/fnives/test/showcase/ui/splash/SplashRobot.kt b/app/src/sharedTest/java/org/fnives/test/showcase/ui/splash/SplashRobot.kt index 5ed4439..095fea3 100644 --- a/app/src/sharedTest/java/org/fnives/test/showcase/ui/splash/SplashRobot.kt +++ b/app/src/sharedTest/java/org/fnives/test/showcase/ui/splash/SplashRobot.kt @@ -1,12 +1,8 @@ package org.fnives.test.showcase.ui.splash -import android.app.Instrumentation import androidx.test.espresso.intent.Intents import androidx.test.espresso.intent.matcher.IntentMatchers -import org.fnives.test.showcase.network.mockserver.MockServerScenarioSetup -import org.fnives.test.showcase.testutils.configuration.MainDispatcherTestRule import org.fnives.test.showcase.testutils.robot.Robot -import org.fnives.test.showcase.testutils.statesetup.SetupAuthenticationState import org.fnives.test.showcase.testutils.viewactions.notIntended import org.fnives.test.showcase.ui.auth.AuthActivity import org.fnives.test.showcase.ui.home.MainActivity @@ -15,33 +11,12 @@ class SplashRobot : Robot { override fun init() { Intents.init() - Intents.intending(IntentMatchers.hasComponent(MainActivity::class.java.canonicalName)) - .respondWith(Instrumentation.ActivityResult(0, null)) - Intents.intending(IntentMatchers.hasComponent(AuthActivity::class.java.canonicalName)) - .respondWith(Instrumentation.ActivityResult(0, null)) } override fun release() { Intents.release() } - fun setupLoggedInState( - mainDispatcherTestRule: MainDispatcherTestRule, - mockServerScenarioSetup: MockServerScenarioSetup - ) { - SetupAuthenticationState.setupLogin(mainDispatcherTestRule, mockServerScenarioSetup) - release() - init() - } - - fun setupLoggedOutState( - mainDispatcherTestRule: MainDispatcherTestRule - ) { - SetupAuthenticationState.setupLogout(mainDispatcherTestRule) - release() - init() - } - fun assertHomeIsStarted() = apply { Intents.intended(IntentMatchers.hasComponent(MainActivity::class.java.canonicalName)) }