在撰写 UI 测试中添加意图附加内容

asc*_*sco 10 android ui-testing android-jetpack-compose

我想对使用Jetpack Compose 的Activity 进行 UI 测试。该文档提供了有关如何使用两种变体测试此类屏幕的一些信息:

 @get:Rule val composeTestRule = createComposeRule()
Run Code Online (Sandbox Code Playgroud)

如果我不需要活动本身运行并且只想测试我的可组合项或

 @get:Rule val composeTestRule = createAndroidComposeRule<MyActivity>()
Run Code Online (Sandbox Code Playgroud)

如果我确实需要这项活动。

在第二种情况下,我如何将带有 Extras 的 Intent 传递给活动?

我试过了:

@Before
fun setUp() {
    composeTestRule.activity.intent = Intent().apply {
        putExtra(
            "someKey",
            123
        )
    }
}
Run Code Online (Sandbox Code Playgroud)

但活动中的意图额外内容仍然为空。

rya*_*en8 8

composeTestRule.activity.intent设置的问题setUp()是活动已经在此时创建并且活动OnCreate已经被调用。因此,您正在设置的意图属性setUp()正在被设置,但为时已晚,无法在Activity.OnCreate.

不幸的是,Google 还没有创建像 那样的辅助方法createAndroidComposeRule<MyActivity>()。不过,可以编写一个辅助方法来解决:

选项 1(每个测试一个意图)

如何使用

class MyActivityTest {

    @get:Rule
    val composeRule = createEmptyComposeRule()

    @Test
    fun firstTimeLogIn() = composeRule.launch<MyActivity>(
        onBefore = {
            // Set up things before the intent
        },
        intentFactory = {
            Intent(it, MyActivity::class.java).apply {
                putExtra("someKey", 123)
            }
        },
        onAfterLaunched = {
            // Assertions on the view 
            onNodeWithText("Username").assertIsDisplayed()
        })
}
Run Code Online (Sandbox Code Playgroud)

Kotlin 扩展辅助方法

import android.app.Activity
import android.content.Context
import android.content.Intent
import androidx.compose.ui.test.junit4.ComposeTestRule
import androidx.compose.ui.test.junit4.createEmptyComposeRule
import androidx.test.core.app.ActivityScenario
import androidx.test.core.app.ApplicationProvider

/**
* Uses a [ComposeTestRule] created via [createEmptyComposeRule] that allows setup before the activity
* is launched via [onBefore]. Assertions on the view can be made in [onAfterLaunched].
*/
inline fun <reified A: Activity> ComposeTestRule.launch(
    onBefore: () -> Unit = {},
    intentFactory: (Context) -> Intent = { Intent(ApplicationProvider.getApplicationContext(), A::class.java) },
    onAfterLaunched: ComposeTestRule.() -> Unit
) {
    onBefore()

    val context = ApplicationProvider.getApplicationContext<Context>()
    ActivityScenario.launch<A>(intentFactory(context))

    onAfterLaunched()
}
Run Code Online (Sandbox Code Playgroud)

选项 2(每个测试单一意图)

如何使用

@RunWith(AndroidJUnit4::class)
class MyActivityTest {

    @get:Rule
    val composeTestRule = createAndroidIntentComposeRule<MyActivity> {
        Intent(it, MyActivity::class.java).apply {
            putExtra("someKey", 123)
        }
    }

    @Test
    fun Test1() {

    }

}
Run Code Online (Sandbox Code Playgroud)

Kotlin 扩展辅助方法

import android.content.Context
import android.content.Intent
import androidx.activity.ComponentActivity
import androidx.compose.ui.test.junit4.AndroidComposeTestRule
import androidx.test.core.app.ApplicationProvider
import androidx.test.ext.junit.rules.ActivityScenarioRule

/**
* Factory method to provide Android specific implementation of createComposeRule, for a given
* activity class type A that needs to be launched via an intent.
*
* @param intentFactory A lambda that provides a Context that can used to create an intent. A intent needs to be returned.
*/
inline fun <A: ComponentActivity> createAndroidIntentComposeRule(intentFactory: (context: Context) -> Intent) : AndroidComposeTestRule<ActivityScenarioRule<A>, A> {
    val context = ApplicationProvider.getApplicationContext<Context>()
    val intent = intentFactory(context)

    return AndroidComposeTestRule(
        activityRule = ActivityScenarioRule(intent),
        activityProvider = { scenarioRule -> scenarioRule.getActivity() }
    )
}

/**
* Gets the activity from a scenarioRule.
*
* https://androidx.tech/artifacts/compose.ui/ui-test-junit4/1.0.0-alpha11-source/androidx/compose/ui/test/junit4/AndroidComposeTestRule.kt.html
*/
fun <A : ComponentActivity> ActivityScenarioRule<A>.getActivity(): A {
    var activity: A? = null

    scenario.onActivity { activity = it }

    return activity ?: throw IllegalStateException("Activity was not set in the ActivityScenarioRule!")
}
Run Code Online (Sandbox Code Playgroud)

  • @Maragues - 好点。我更新了一个选项,该选项使用扩展方法来为每个测试设置意图。 (2认同)