Android Native - Drive Activity States in Espresso Tests

dimitrilc 2 Tallied Votes 65 Views Share

Introduction

When working on Espresso tests, you might have run into a situation where you need to verify what your app does when an activity is in a specific Lifecycle state. In this tutorial, we will learn how to achieve this by using the ActivityScenario class.

Goals

At the end of the tutorial, you would have learned:

  1. How to drive an Activity’s lifecycle.

Tools Required

  1. Android Studio. The version used in this tutorial is Android Studio Dolphin | 2021.3.1.

Prerequisite Knowledge

  1. Basic Android.
  2. Basic Espresso.

Project Setup

To follow along with the tutorial, perform the steps below:

  1. Create a new Android project with the default Empty Activity.

  2. Replace the entire content of the MainActivity.kt class with the code below. This is just a simple Activity that logs some text at onCreate(), onStart(), onResume(), and onDestroy() methods.

     private const val TAG = "MAIN_ACTIVITY"
    
     class MainActivity : AppCompatActivity() {
        override fun onCreate(savedInstanceState: Bundle?) {
            Log.d(TAG, "On Create")
            super.onCreate(savedInstanceState)
            setContentView(R.layout.activity_main)
        }
    
        override fun onStart() {
            Log.d(TAG, "On Start")
            super.onStart()
        }
    
        override fun onResume() {
            Log.d(TAG, "On Resume")
            super.onResume()
        }
    
        override fun onDestroy() {
            Log.d(TAG, "On Destroy")
            super.onDestroy()
        }
     }
  3. In Android Studio’s Logcat, we can use the query below to see the log messages after we run our tests.

     level:debug tag:MAIN_ACTIVITY
  4. In the androidTest source set, remove all test cases from the file named ExampleInstrumentedTest.java.

Use ActivityScenario to Drive Activity States

The two primary methods in the ActivityScenario class that we need to be concerned of for this tutorial is the static factory method launch() and the instance method moveToState().

  1. The launch() methods are used to create the ActivityScenario<A> objects, while the A generic type represents the type of the Activity being driven.
  2. The moveToState() method is used to move the underlying Activity to a different state. The only states that it can move the Activity to are CREATED, STARTED, RESUMED, and DESTROYED.

As a side note, ActivityScenario also implements Closeable. You are recommended to close the Activity after the test completes, so you are recommended to use a Java try-with-resource block or a Kotlin use {} block to automatically close ActivityScenario.

Now it’s time to create our first test. Add the test below into the ExampleInstrumentedTest class.

@Test
fun lifecycleTest(){
   ActivityScenario.launch(MainActivity::class.java).use { scenario ->

   }
}

In the code snippet above, I used the simplest version of launch(), which only requires the Class object of the Activity being tested. The scenario parameter is of type ActivityScenario<MainActivity>. Using the scenario parameter, we can now call moveToState() methods to move the Activity to different states.

@Test
fun lifecycleTest(){
   ActivityScenario.launch(MainActivity::class.java).use { scenario ->
       scenario.moveToState(Lifecycle.State.CREATED)
       scenario.moveToState(Lifecycle.State.STARTED)
       scenario.moveToState(Lifecycle.State.RESUMED)
       scenario.moveToState(Lifecycle.State.RESUMED)
       scenario.moveToState(Lifecycle.State.RESUMED)
       scenario.moveToState(Lifecycle.State.DESTROYED)
   }
}

After running this test, we can see the code in our MainActivity logging when it is at each step.

---------------------------- PROCESS STARTED (10469) for package com.hoang.daniwebandroidactivityscenario ----------------------------
2022-09-28 17:52:59.082 10469-10469 MAIN_ACTIVITY           com...aniwebandroidactivityscenario  D  On Create
2022-09-28 17:52:59.117 10469-10469 MAIN_ACTIVITY           com...aniwebandroidactivityscenario  D  On Start
2022-09-28 17:52:59.118 10469-10469 MAIN_ACTIVITY           com...aniwebandroidactivityscenario  D  On Resume
2022-09-28 17:52:59.328 10469-10469 MAIN_ACTIVITY           com...aniwebandroidactivityscenario  D  On Start
2022-09-28 17:52:59.328 10469-10469 MAIN_ACTIVITY           com...aniwebandroidactivityscenario  D  On Resume
2022-09-28 17:52:59.393 10469-10469 MAIN_ACTIVITY           com...aniwebandroidactivityscenario  D  On Resume
2022-09-28 17:52:59.506 10469-10469 MAIN_ACTIVITY           com...aniwebandroidactivityscenario  D  On Destroy
---------------------------- PROCESS ENDED (10469) for package com.hoang.daniwebandroidactivityscenario ----------------------------

ActivityScenario vs. ActivityScenarioRule

Android also comes with the ActivityScenarioRule, which is the more preferable method over using ActivityScenario directly. ActivityScenarioRule can automatically handle starting and closing the ActivityScenario for us. It also reduces verbosity because we do not have to call the launch() method again every time we need it.

To use ActivityScenarioRule, declare it in the class ExampleInstrumentedTest (for Kotlin, Java users can just use the @Rule annotation).

@get:Rule
val rule = ActivityScenarioRule(MainActivity::class.java)

@Test
fun lifeCycleTestWithRule() {
   val scenario = rule.scenario
   scenario.moveToState(Lifecycle.State.CREATED)
   scenario.moveToState(Lifecycle.State.STARTED)
   scenario.moveToState(Lifecycle.State.RESUMED)
   scenario.moveToState(Lifecycle.State.RESUMED)
   scenario.moveToState(Lifecycle.State.RESUMED)
   scenario.moveToState(Lifecycle.State.DESTROYED)
}

To access the ActivityScenario object in the test, either call getScenario() (Java) or use property accessor syntax in Kotlin (used in example above).

Summary

In this tutorial, we have learned how to use ActivityScenario/ActivityScenarioRule to drive Activity state in our tests. The full project code can be found at https://github.com/dmitrilc/DaniwebAndroidActivityScenario.

Be a part of the DaniWeb community

We're a friendly, industry-focused community of developers, IT pros, digital marketers, and technology enthusiasts meeting, networking, learning, and sharing knowledge.