在撰写 UI 测试中添加意图附加功能

问题描述 投票:0回答:3

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

 @get:Rule val composeTestRule = createComposeRule()

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

 @get:Rule val composeTestRule = createAndroidComposeRule<MyActivity>()

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

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

我已经尝试过:

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

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

android android-jetpack-compose ui-testing
3个回答
6
投票

composeTestRule.activity.intent
中设置
setUp()
的问题是 Activity 已在此时创建,并且 Activity 的
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()
        })
}

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

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

如何使用

@RunWith(AndroidJUnit4::class)
class MyActivityTest {

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

    @Test
    fun Test1() {

    }

}

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

3
投票
class ActivityTest {

    private lateinit var scenario: ActivityScenario<Activity>

    @get:Rule
    val composeAndroidRule = createEmptyComposeRule()


    @Before
    fun setUp() {

        scenario = ActivityScenario.launch(
            createActivityIntent(
                InstrumentationRegistry.getInstrumentation().targetContext,
            )
        )
    }

    private fun createActivityIntent(
        context: Context
    ): Intent {
        val intent = Intent(context, Activity::class.java)
        return intent
    }

}

希望此代码片段对您有用


-2
投票

这是一个简单的解决方案:

@Before
fun setUp() {
    composeTestRule.activity.intent.apply {
        putExtra(
            "someKey",
            123
        )
    }
}
© www.soinside.com 2019 - 2024. All rights reserved.