3

I am developing an Android application using Kotlin programming language. I am adding instrumentation tests into my application. Now I am trying to test if an activity is started after some delay.

This is my activity code.

class MainActivity : AppCompatActivity() {

    companion object {
        val LAUNCH_DELAY: Long = 2000
    }

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)
        Handler().postDelayed({
            this.startLoginActivity()
        }, LAUNCH_DELAY)
    }

    protected fun startLoginActivity()
    {
        startActivity(Intent(this, LoginActivity::class.java))
    }
}

I know how to write a simple test like this

@Test
fun itRendersCompanyName() {
    onView(withId(R.id.main_tv_company_name)).check(matches(withText("App Name")))
}

But what I am trying to test here is if the LoginActivity is launched after some delay. How can I do it using Espresso framework?

halfer
  • 19,824
  • 17
  • 99
  • 186
Wai Yan Hein
  • 13,651
  • 35
  • 180
  • 372

4 Answers4

4

You can get the visible Activity using ActivityManager:

inline fun <reified T : Activity> isVisible(): Boolean {
    val am = ApplicationProvider.getApplicationContext<Context>().getSystemService(ACTIVITY_SERVICE)
            as ActivityManager

    val visibleActivityName = if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.M) {
        am.appTasks[0].taskInfo.topActivity.className
    } else {
        am.getRunningTasks(1)[0].topActivity.className
    }
    return visibleActivityName == T::class.java.name
}

Calling isVisible<LoginActivity>() will tell you that LoginActivity is visible or not.

Also, to wait until your LoginActivity visible, you can wait for this method to gets true. For example:

inline fun <reified T : Activity> waitUntilActivityVisible() {
    val startTime = System.currentTimeMillis()
    while (!isVisible<T>()) {
        Thread.sleep(200)
        if (System.currentTimeMillis() - startTime >= TIMEOUT) {
            throw AssertionError("Condition unsatisfied after $TIMEOUT milliseconds")
        }
    }
}
Saeed Masoumi
  • 8,746
  • 7
  • 57
  • 76
  • I recommend checking for null in appTasks getter: val visibleActivityName = am.appTasks.elementAtOrNull(0)?.taskInfo?.baseActivity?.className – tonisives Oct 09 '20 at 03:14
1

You can use Intents.intended() for that.

Add following to your build.gradle file:

androidTestImplementation 'androidx.test.espresso:espresso-intents:3.1.0'

In your test function, you can try following code:

Intents.init()
Intents.intended(hasComponent(LoginActivity::class.java!!.getName()))

You can read more about Espresso-Intents here.

Natig Babayev
  • 3,128
  • 15
  • 23
1

It’s better to test this state with unit tests. Use architecture pattern (for example MVP/MVVM), mock presenter/view model and check what method which is responsible for activity start is triggered

Peter Staranchuk
  • 1,343
  • 3
  • 14
  • 29
0

I got it working using the following:

val expectedUrl = "https://yoururlhere"    
Intents.init();
Matcher<Intent> expectedIntent = allOf(hasAction(Intent.ACTION_VIEW), hasData(expectedUrl));
intending(expectedIntent).respondWith(new Instrumentation.ActivityResult(0, null));
onView(withId(R.id.someViewId)).perform(click());
intended(expectedIntent);
Intents.release();

And remember to add "androidTestImplementation 'androidx.test.espresso:espresso-intents:3.1.0'" to your gradle dependency