Issue#67 Extract MainThread synchronization into a separate module

This commit is contained in:
Gergely Hegedus 2022-05-27 15:41:20 +03:00
parent 1c0153db75
commit bbe077dde8
8 changed files with 36 additions and 42 deletions

View file

@ -16,7 +16,7 @@ import org.fnives.test.showcase.testutils.idling.CompositeDisposable
import org.fnives.test.showcase.testutils.idling.Disposable import org.fnives.test.showcase.testutils.idling.Disposable
import org.fnives.test.showcase.testutils.idling.IdlingResourceDisposable import org.fnives.test.showcase.testutils.idling.IdlingResourceDisposable
import org.fnives.test.showcase.testutils.idling.OkHttp3IdlingResource import org.fnives.test.showcase.testutils.idling.OkHttp3IdlingResource
import org.fnives.test.showcase.testutils.idling.loopMainThreadFor import org.fnives.test.showcase.android.testutil.synchronization.loopMainThreadFor
import org.fnives.test.showcase.testutils.storage.TestDatabaseInitialization import org.fnives.test.showcase.testutils.storage.TestDatabaseInitialization
import org.fnives.test.showcase.ui.splash.SplashActivity import org.fnives.test.showcase.ui.splash.SplashActivity
import org.hamcrest.Description import org.hamcrest.Description

View file

@ -1,12 +1,8 @@
package org.fnives.test.showcase.testutils.idling package org.fnives.test.showcase.testutils.idling
import android.os.Looper
import androidx.test.espresso.Espresso
import androidx.test.espresso.IdlingRegistry import androidx.test.espresso.IdlingRegistry
import androidx.test.espresso.IdlingResource import androidx.test.espresso.IdlingResource
import androidx.test.espresso.matcher.ViewMatchers import org.fnives.test.showcase.android.testutil.synchronization.loopMainThreadFor
import org.fnives.test.showcase.testutils.viewactions.LoopMainThreadFor
import org.fnives.test.showcase.testutils.viewactions.LoopMainThreadUntilIdle
import java.util.concurrent.Executors import java.util.concurrent.Executors
// workaround, issue with idlingResources is tracked here https://github.com/robolectric/robolectric/issues/4807 // workaround, issue with idlingResources is tracked here https://github.com/robolectric/robolectric/issues/4807
@ -41,20 +37,3 @@ private fun IdlingResource.awaitUntilIdle() {
Thread.sleep(100L) Thread.sleep(100L)
} }
} }
fun loopMainThreadUntilIdleWithIdlingResources() {
Espresso.onView(ViewMatchers.isRoot()).perform(LoopMainThreadUntilIdle()) // advance until a request is sent
while (anyResourceIdling()) { // check if any request is in progress
awaitIdlingResources() // complete all requests and other idling resources
Espresso.onView(ViewMatchers.isRoot()).perform(LoopMainThreadUntilIdle()) // run coroutines after request is finished
}
Espresso.onView(ViewMatchers.isRoot()).perform(LoopMainThreadUntilIdle())
}
fun loopMainThreadFor(delay: Long) {
if (Looper.getMainLooper().isCurrentThread) {
Thread.sleep(200L)
} else {
Espresso.onView(ViewMatchers.isRoot()).perform(LoopMainThreadFor(delay))
}
}

View file

@ -3,6 +3,7 @@ package org.fnives.test.showcase.ui.home
import androidx.test.core.app.ActivityScenario import androidx.test.core.app.ActivityScenario
import androidx.test.espresso.intent.Intents import androidx.test.espresso.intent.Intents
import androidx.test.ext.junit.runners.AndroidJUnit4 import androidx.test.ext.junit.runners.AndroidJUnit4
import org.fnives.test.showcase.android.testutil.activity.safeClose
import org.fnives.test.showcase.model.content.FavouriteContent import org.fnives.test.showcase.model.content.FavouriteContent
import org.fnives.test.showcase.network.mockserver.ContentData 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.content.ContentScenario
@ -10,9 +11,7 @@ import org.fnives.test.showcase.network.mockserver.scenario.refresh.RefreshToken
import org.fnives.test.showcase.testutils.MockServerScenarioSetupResetingTestRule import org.fnives.test.showcase.testutils.MockServerScenarioSetupResetingTestRule
import org.fnives.test.showcase.testutils.idling.AsyncDiffUtilInstantTestRule import org.fnives.test.showcase.testutils.idling.AsyncDiffUtilInstantTestRule
import org.fnives.test.showcase.testutils.idling.MainDispatcherTestRule import org.fnives.test.showcase.testutils.idling.MainDispatcherTestRule
import org.fnives.test.showcase.testutils.idling.loopMainThreadFor import org.fnives.test.showcase.android.testutil.synchronization.loopMainThreadFor
import org.fnives.test.showcase.testutils.idling.loopMainThreadUntilIdleWithIdlingResources
import org.fnives.test.showcase.android.testutil.activity.safeClose
import org.fnives.test.showcase.testutils.statesetup.SetupAuthenticationState.setupLogin import org.fnives.test.showcase.testutils.statesetup.SetupAuthenticationState.setupLogin
import org.junit.After import org.junit.After
import org.junit.Before import org.junit.Before
@ -175,9 +174,6 @@ class MainActivityInstrumentedTest : KoinTest {
robot.swipeRefresh() robot.swipeRefresh()
mainDispatcherTestRule.advanceUntilIdleWithIdlingResources() mainDispatcherTestRule.advanceUntilIdleWithIdlingResources()
loopMainThreadUntilIdleWithIdlingResources()
mainDispatcherTestRule.advanceTimeBy(1000L)
loopMainThreadFor(1000)
robot robot
.assertContainsError() .assertContainsError()

View file

@ -30,5 +30,5 @@ project.ext {
testing_json_assert_version = "1.5.0" testing_json_assert_version = "1.5.0"
testing_junit4_version = "4.12" testing_junit4_version = "4.12"
testing_robolectric_version = "4.7" testing_robolectric_version = "4.7"
testing_espresso_version = "3.4.0" espresso_version = "3.4.0"
} }

View file

@ -32,4 +32,5 @@ android {
dependencies { dependencies {
implementation "org.jetbrains.kotlinx:kotlinx-coroutines-test:$coroutines_version" implementation "org.jetbrains.kotlinx:kotlinx-coroutines-test:$coroutines_version"
implementation "androidx.test:core:$androidx_test_version" implementation "androidx.test:core:$androidx_test_version"
implementation"androidx.test.espresso:espresso-core:$espresso_version"
} }

View file

@ -2,8 +2,11 @@ package org.fnives.test.showcase.android.testutil.synchronization
import android.os.Handler import android.os.Handler
import android.os.Looper import android.os.Looper
import androidx.test.espresso.Espresso
import androidx.test.espresso.matcher.ViewMatchers
import kotlinx.coroutines.CompletableDeferred import kotlinx.coroutines.CompletableDeferred
import kotlinx.coroutines.runBlocking import kotlinx.coroutines.runBlocking
import org.fnives.test.showcase.android.testutil.viewaction.LoopMainThreadFor
/** /**
* Runs the given action on the MainThread and blocks currentThread, until it is completed. * Runs the given action on the MainThread and blocks currentThread, until it is completed.
@ -22,3 +25,11 @@ fun runOnUIAwaitOnCurrent(action: () -> Unit) {
runBlocking { deferred.await() } runBlocking { deferred.await() }
} }
} }
fun loopMainThreadFor(delay: Long) {
if (Looper.getMainLooper().thread == Thread.currentThread()) {
Thread.sleep(200L)
} else {
Espresso.onView(ViewMatchers.isRoot()).perform(LoopMainThreadFor(delay))
}
}

View file

@ -1,4 +1,4 @@
package org.fnives.test.showcase.testutils.viewactions package org.fnives.test.showcase.android.testutil.viewaction
import android.view.View import android.view.View
import androidx.test.espresso.UiController import androidx.test.espresso.UiController
@ -15,13 +15,3 @@ class LoopMainThreadFor(private val delayInMillis: Long) : ViewAction {
uiController.loopMainThreadForAtLeast(delayInMillis) uiController.loopMainThreadForAtLeast(delayInMillis)
} }
} }
class LoopMainThreadUntilIdle : ViewAction {
override fun getConstraints(): Matcher<View> = Matchers.isA(View::class.java)
override fun getDescription(): String = "loop MainThread for until Idle"
override fun perform(uiController: UiController, view: View?) {
uiController.loopMainThreadUntilIdle()
}
}

View file

@ -0,0 +1,17 @@
package org.fnives.test.showcase.android.testutil.viewaction
import android.view.View
import androidx.test.espresso.UiController
import androidx.test.espresso.ViewAction
import org.hamcrest.Matcher
import org.hamcrest.Matchers
class LoopMainThreadUntilIdle : ViewAction {
override fun getConstraints(): Matcher<View> = Matchers.isA(View::class.java)
override fun getDescription(): String = "loop MainThread for until Idle"
override fun perform(uiController: UiController, view: View?) {
uiController.loopMainThreadUntilIdle()
}
}