Android仪器化测试:断言某个Activity是否已启动

3

我正在使用Kotlin编程语言开发一个Android应用程序,现在我想将仪器化测试添加到我的应用程序中。 我现在正在尝试测试是否在一定延迟后启动了一个活动。

这是我的活动代码:

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))
    }
}

我知道如何编写像这样的简单测试

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

但我现在想测试的是,是否可以使用Espresso框架在一定延迟后启动LoginActivity。该怎么做呢?

4个回答

4
您可以使用ActivityManager获取可见的Activity:
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
}

调用isVisible<LoginActivity>()可以告诉您LoginActivity是否可见。

此外,要等待您的LoginActivity可见,您可以等待此方法得到true。例如:

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")
        }
    }
}

我建议在获取appTasks时检查是否为null:val visibleActivityName = am.appTasks.elementAtOrNull(0)?.taskInfo?.baseActivity?.className - tonisives

1
最好使用单元测试来测试这个状态。使用架构模式(例如MVP/MVVM),模拟Presenter/ViewModel并检查负责启动活动的方法是否被触发。

1
如何测试 Android 中的方法是否被触发? - Wai Yan Hein
1
Mockito.verify(mockedClass).someMethod(parameters) - Peter Staranchuk
在@Before中:presenter = Mockito.spy(SomePresenter(...))在测试中: Mockito.verify(presenter, times(1)).startLoginActivity()其中times(1)表示确切地进行了一次交互。 - Peter Staranchuk

1
你可以使用 Intents.intended() 来实现这一功能。
将以下内容添加到你的 build.gradle 文件中:
androidTestImplementation 'androidx.test.espresso:espresso-intents:3.1.0'

在您的测试函数中,您可以尝试以下代码:
Intents.init()
Intents.intended(hasComponent(LoginActivity::class.java!!.getName()))

你可以在这里了解更多关于Espresso-Intents的内容。


请问您能否指定完整的类名或命名空间? - Wai Yan Hein
这是带有包名的类名:androidx.test.espresso.intent.Intents - Natig Babayev
在调用intended()函数之前,不要忘记添加Thread.sleep(2000),因为根据你的代码,你的操作将在2秒后执行。 - Natig Babayev
谢谢您的回答。但我还有另一个问题。请参考https://stackoverflow.com/questions/58049150/android-kotlin-expresso-asserting-intended-activity-in-the-unit-test-is-throwing - Wai Yan Hein
你尝试在调用Intents.intended()之前添加Thread.sleep(2000)了吗? - Natig Babayev
显示剩余10条评论

0

我使用以下方法使其正常工作:

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();

记得将 "androidTestImplementation 'androidx.test.espresso:espresso-intents:3.1.0'" 添加到您的 gradle 依赖中


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接