Skip to content

Resource Idling: Calling a time consuming function

Devrath edited this page Feb 28, 2024 · 1 revision

Scenario

  • We have a text and a button
  • Initially the text shows Not started state
  • On clicking on the button, We change the text to Started and perform the long-running operation.
  • Once the long-running operation is complete, we change the text to Complete.

Screen

demo.webm

Test

@RunWith(AndroidJUnit4::class)
@LargeTest
class ResourceIdlingActivityTest {

    // SUT
    @get:Rule
    val activityRule = ActivityScenarioRule(ResourceIdlingActivity::class.java)

    // Our network manager
    private val networkManager = NetworkManager()
    // Create and register the custom IdlingResource
    private val networkIdlingResource = NetworkIdlingResource(networkManager)

    @Before
    fun setUp() {
        IdlingRegistry.getInstance().register(networkIdlingResource)
    }

    @After
    fun tearDown() {
        // Unregister the IdlingResource
        IdlingRegistry.getInstance().unregister(networkIdlingResource)
    }


    @Test
    fun testNetworkRequest() {

        // Perform UI interactions - onClick of button
        Espresso.onView(withId(R.id.btnResourceIdlingId))
            .perform(click())

        // Perform the network request and wait for it to complete
        networkIdlingResource.performNetworkRequestAndWait()

        // Perform assertions
        Espresso.onView(withId(R.id.txtInputFieldId))
            .check(matches(withText("Complete")))
    }
}

NetworkIdlingResource.kt

class NetworkIdlingResource(private val networkManager: NetworkManager) : IdlingResource {

    private val isIdleNow = AtomicBoolean(true)
    private var callback: IdlingResource.ResourceCallback? = null

    override fun getName(): String {
        // Provide the current class implementation name
        return NetworkIdlingResource::class.java.name
    }

    override fun registerIdleTransitionCallback(callback: IdlingResource.ResourceCallback?) {
        this.callback = callback
    }

    override fun isIdleNow(): Boolean {
        return isIdleNow.get()
    }

    fun performNetworkRequestAndWait() {
        isIdleNow.set(false)

        // Perform the network request
        networkManager.performNetworkRequest {
            // Callback when the network request is complete
            isIdleNow.set(true)

            callback?.onTransitionToIdle()
        }
    }

}

Code

ResourceIdlingActivity.kt

class ResourceIdlingActivity : AppCompatActivity() {

    private lateinit var binding: ActivityResourceIdlingBinding

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        binding = ActivityResourceIdlingBinding.inflate(layoutInflater)
        setContentView(binding.root)

        binding.btnResourceIdlingId.setOnClickListener {
            val manager = NetworkManager()
            // Request started
            binding.txtInputFieldId.text = "Started"
            manager.performNetworkRequest {
                // Request complete
                binding.txtInputFieldId.text = "Complete"
            }

        }
    }

}

NetworkManager.kt

class NetworkManager {

    companion object {
        const val NETWORK_DELAY : Long = 3000
    }

    fun performNetworkRequest(callback :()-> Unit){

        // Simulating a network request that takes some time
        Handler(Looper.getMainLooper()).postDelayed({
            // Invoking the callback
            callback.invoke()
        }, NETWORK_DELAY)

    }

}

activity_resource_idling.xml

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:gravity="center"
    android:padding="20dp"
    android:orientation="vertical"
    tools:context=".demos.MainActivity">

   <TextView
       android:id="@+id/txtInputFieldId"
       android:layout_width="match_parent"
       android:layout_height="wrap_content"
       android:gravity="center"
       android:textSize="22sp"
       android:textStyle="bold"
       android:text="Not started"/>

    <Button
        android:id="@+id/btnResourceIdlingId"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:text="Change text"/>

</LinearLayout>