launchFragmentInContainer 无法解析 Activity 的意图

Dev*_*inM 0 android unit-testing

尝试在仪器测试中使用 FragmentScenario 时,我收到以下错误。我认为这个问题与构建类型有关,因为测试是在“staging”而不是“debug”构建配置下运行的。

\n

任何帮助将不胜感激。

\n

错误

\n
java.lang.RuntimeException: Unable to resolve activity for: Intent { act=android.intent.action.MAIN cat=[android.intent.category.LAUNCHER] cmp=com.example/androidx.fragment.app.testing.FragmentScenario$EmptyFragmentActivity (has extras) }\nat androidx.test.core.app.InstrumentationActivityInvoker.startActivity(InstrumentationActivityInvoker.java:387)\nat androidx.test.core.app.InstrumentationActivityInvoker.startActivity(InstrumentationActivityInvoker.java:416)\nat androidx.test.core.app.ActivityScenario.launchInternal(ActivityScenario.java:265)\nat androidx.test.core.app.ActivityScenario.launch(ActivityScenario.java:226)\nat androidx.fragment.app.testing.FragmentScenario.internalLaunch(FragmentScenario.java:299)\nat androidx.fragment.app.testing.FragmentScenario.launchInContainer(FragmentScenario.java:282)\nat com.example.view.fragments.MainFragmentTest.testNavigation(MainFragmentTest.kt:139)\nat java.lang.reflect.Method.invoke(Native Method)\nat org.junit.runners.model.FrameworkMethod$1.runReflectiveCall(FrameworkMethod.java:59)\nat org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:12)\nat org.junit.runners.model.FrameworkMethod.invokeExplosively(FrameworkMethod.java:56)\nat org.junit.internal.runners.statements.InvokeMethod.evaluate(InvokeMethod.java:17)\nat androidx.test.internal.runner.junit4.statement.RunBefores.evaluate(RunBefores.java:80)\nat androidx.test.internal.runner.junit4.statement.RunAfters.evaluate(RunAfters.java:61)\nat androidx.test.rule.ActivityTestRule$ActivityStatement.evaluate(ActivityTestRule.java:549)\nat org.junit.runners.ParentRunner$3.evaluate(ParentRunner.java:306)\nat org.junit.runners.BlockJUnit4ClassRunner$1.evaluate(BlockJUnit4ClassRunner.java:100)\nat org.junit.runners.ParentRunner.runLeaf(ParentRunner.java:366)\nat org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:103)\nat org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:63)\nat org.junit.runners.ParentRunner$4.run(ParentRunner.java:331)\nat org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:79)\nat org.junit.runners.ParentRunner.runChildren(ParentRunner.java:329)\nat org.junit.runners.ParentRunner.access$100(ParentRunner.java:66)\nat org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:293)\nat org.junit.runners.ParentRunner$3.evaluate(ParentRunner.java:306)\nat org.junit.runners.ParentRunner.run(ParentRunner.java:413)\nat androidx.test.ext.junit.runners.AndroidJUnit4.run(AndroidJUnit4.java:154)\nat org.junit.runners.Suite.runChild(Suite.java:128)\nat org.junit.runners.Suite.runChild(Suite.java:27)\nat org.junit.runners.ParentRunner$4.run(ParentRunner.java:331)\nat org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:79)\nat org.junit.runners.ParentRunner.runChildren(ParentRunner.java:329)\nat org.junit.runners.ParentRunner.access$100(ParentRunner.java:66)\nat org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:293)\nat org.junit.runners.ParentRunner$3.evaluate(ParentRunner.java:306)\nat org.junit.runners.ParentRunner.run(ParentRunner.java:413)\nat org.junit.runner.JUnitCore.run(JUnitCore.java:137)\nat org.junit.runner.JUnitCore.run(JUnitCore.java:115)\nat androidx.test.internal.runner.TestExecutor.execute(TestExecutor.java:56)\nat androidx.test.runner.AndroidJUnitRunner.onStart(AndroidJUnitRunner.java:395)\nat android.app.Instrumentation$InstrumentationThread.run(Instrumentation.java:2189)\n
Run Code Online (Sandbox Code Playgroud)\n

正在运行的测试是谷歌关于测试导航的文档的吐槽图片https://developer.android.com/guide/navigation/navigation-testing#kotlin

\n
@Test\nfun testNavigation() {\n    // Create a TestNavHostController\n    val navController = TestNavHostController(ApplicationProvider.getApplicationContext())\n    navController.setGraph(R.navigation.nav_graph)\n\n    // Create a graphical FragmentScenario for the TitleScreen\n    // Without adding androidTestImplementation "...fragment-testing" to the build gradle this errors and cannot build. This is because we are in staging variant instead of debug variant.\n    val fragmentScenario = launchFragmentInContainer<MainFragment>()\n\n    // Set the NavController property on the fragment\n    fragmentScenario.onFragment { fragment ->\n        Navigation.setViewNavController(fragment.requireView(), navController)\n    }\n\n    // Verify that performing a click changes the NavController\xe2\x80\x99s state\n    onView(withId(R.id.login)).perform(click())\n    assertThat(navController.currentDestination?.id.toString(), equalTo(R.id.dashboardFragment.toString()))\n}\n
Run Code Online (Sandbox Code Playgroud)\n

显现

\n
<?xml version="1.0" encoding="utf-8"?>\n<manifest\n    xmlns:android="http://schemas.android.com/apk/res/android"\n    xmlns:tools="http://schemas.android.com/tools"\n    package="com.example">\n\n    ....\n\n    <application\n        android:name=".Example"\n        android:allowBackup="true"\n        android:fullBackupContent="true"\n        android:icon="@mipmap/ic_launcher"\n        android:label="@string/app_name"\n        android:requestLegacyExternalStorage="true"\n        android:roundIcon="@mipmap/ic_launcher_round"\n        android:supportsRtl="true"\n        android:theme="@style/AppTheme"\n        android:usesCleartextTraffic="${cleartextTrafficPermitted}">\n\n        <activity\n            android:name="com.example.controllers.LauncherActivity"\n            android:screenOrientation="portrait"\n            android:theme="@style/AppTheme.Launcher"\n            tools:ignore="LockedOrientationActivity"\n            android:windowSoftInputMode="stateHidden|adjustResize">\n\n            <intent-filter>\n                <action android:name="android.intent.action.MAIN" />\n                <category android:name="android.intent.category.LAUNCHER" />\n            </intent-filter>\n\n        </activity>\n\n        <activity\n            android:name="com.example.controllers.MainActivity"\n            android:screenOrientation="portrait"\n            android:windowSoftInputMode="stateHidden|adjustResize"\n            android:theme="@style/AppTheme.Launcher"\n            tools:ignore="LockedOrientationActivity" />\n\n        ...\n\n    </application>\n\n</manifest>\n
Run Code Online (Sandbox Code Playgroud)\n

构建.gradle(应用程序)

\n
apply plugin: \'com.android.application\'\napply plugin: \'kotlin-android\'\napply plugin: \'kotlin-android-extensions\'\napply plugin: \'kotlin-kapt\'\napply plugin: \'com.google.firebase.crashlytics\'\napply plugin: \'com.google.gms.google-services\'\napply plugin: "androidx.navigation.safeargs.kotlin"\n\next.okhttp_version = \'4.7.2\'\next.retrofit_version = \'2.9.0\'\next.mockito_version = \'3.3.3\'\next.coroutine_version = \'1.3.9\'\next.test_version = \'1.3.0\'\next.fragment_version = \'1.2.5\'\next.nav_version = \'2.3.0\'\n\nandroid {\n    compileSdkVersion 29\n    buildToolsVersion "29.0.3"\n\n    testBuildType "staging"\n\n    defaultConfig {\n        applicationId "com.example"\n        minSdkVersion 23\n        targetSdkVersion 29\n        versionCode 1\n        versionName "1.0.0"\n\n        testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"\n\n        vectorDrawables.useSupportLibrary = true\n    }\n\n    buildTypes {\n        debug {\n            buildConfigField "String", "API_DOMAIN", \'"https://testing.com"\'\n\n            // This is needed when API\'s are connecting to HTTP endpoints. Primary purpose is\n            // for the staging buildType to use a non-SSL mock server locally.\n            manifestPlaceholders.cleartextTrafficPermitted ="true"\n        }\n\n        staging {\n            initWith(buildTypes.debug)\n            buildConfigField "String", "API_DOMAIN", \'"http://127.0.0.1/"\'\n        }\n\n        release {\n            minifyEnabled false\n            proguardFiles getDefaultProguardFile(\'proguard-android-optimize.txt\'), \'proguard-rules.pro\'\n\n            buildConfigField "String", "API_DOMAIN", \'"https://production.com"\'\n\n            // Production version will not need to access HTTP endpoints. Disable\n            // because it poses a security risk.\n            manifestPlaceholders.cleartextTrafficPermitted ="false"\n        }\n    }\n\n    compileOptions {\n        sourceCompatibility JavaVersion.VERSION_1_8\n        targetCompatibility JavaVersion.VERSION_1_8\n    }\n\n    viewBinding {\n        enabled = true\n    }\n\n    kotlinOptions {\n        jvmTarget = "1.8"\n    }\n\n    testOptions {\n        unitTests.includeAndroidResources = true\n        unitTests.returnDefaultValues = true\n        execution \'ANDROIDX_TEST_ORCHESTRATOR\'\n    }\n}\n\ndependencies {\n    implementation fileTree(dir: \'libs\', include: [\'*.jar\'])\n    \n    ...\n\n    // Test dependencies\n    testImplementation \'junit:junit:4.13\'\n    testImplementation "org.mockito:mockito-inline:$mockito_version"\n    testImplementation "org.mockito:mockito-core:$mockito_version"\n\n    androidTestImplementation \'androidx.test.ext:junit:1.1.2\'\n    androidTestImplementation \'androidx.test.espresso:espresso-core:3.3.0\'\n    androidTestImplementation "org.mockito:mockito-android:$mockito_version"\n    androidTestImplementation "androidx.test:core:$test_version"\n    androidTestImplementation "androidx.test:rules:$test_version"\n    androidTestImplementation "androidx.test:runner:$test_version"\n    androidTestImplementation "com.squareup.okhttp3:mockwebserver:$okhttp_version"\n    androidTestUtil "androidx.test:orchestrator:$test_version"\n\n    // Without this, if I change the active build variant to staging I cannot use FragmentScenario as the IDE returns "unresolved reference"\n    androidTestImplementation "androidx.fragment:fragment-testing:$fragment_version"\n\n    // This is the correct implementation of fragment-testing\n    debugImplementation "androidx.fragment:fragment-testing:$fragment_version"\n\n    androidTestImplementation(\'com.android.support.test.espresso:espresso-contrib:3.0.2\') {\n        // Necessary to avoid version conflicts\n        exclude group: \'com.android.support\', module: \'appcompat\'\n        exclude group: \'com.android.support\', module: \'support-v4\'\n        exclude group: \'com.android.support\', module: \'support-annotations\'\n        exclude module: \'recyclerview-v7\'\n    }\n\n    // Testing Navigation\n    androidTestImplementation "androidx.navigation:navigation-testing:$nav_version"\n\n    ...\n}\n
Run Code Online (Sandbox Code Playgroud)\n

更新

\n

如果我删除 androidTestImplementation 和 debugImplementation 并替换为 stagingImplementation 以便该库可用于暂存构建变体,这会导致所有测试类失败并显示“未找到测试”

\n
// androidTestImplementation "androidx.fragment:fragment-testing:$fragment_version"\n// debugImplementation "androidx.fragment:fragment-testing:$fragment_version"\n//noinspection FragmentGradleConfiguration\nstagingImplementation "androidx.fragment:fragment-testing:$fragment_version"\n
Run Code Online (Sandbox Code Playgroud)\n

ian*_*ake 5

如果您没有针对debug构建运行测试,那么这debugImplementation还不够。您需要添加:

stagingImplementation "androidx.fragment:fragment-testing:$fragment_version"
Run Code Online (Sandbox Code Playgroud)