50

While writing a simple test which uses launchFragmentInContainer, I get the following error message:

java.lang.RuntimeException: Unable to resolve activity for: Intent { act=android.intent.action.MAIN cat=[android.intent.category.LAUNCHER] cmp=com.myapp.appname.debug/androidx.fragment.app.testing.FragmentScenario$EmptyFragmentActivity (has extras) }

The basic test class is:

class OneFragmentTest {

    @Test
    fun testOneFragmentState_checkTitleText() {
        val args = Bundle().apply {
            putString("dummyKey", "dummyValue")
        }
        launchFragmentInContainer<OneFragment>(args)

        onView(withId(R.id.tv_title)).check(matches(withText("title here")))
    }
}

I have tried to update AndroidManifest.xml with the following:

<instrumentation
        android:name="android.test.InstrumentationTestRunner"
        android:targetPackage="com.myapp.appname" />

but it seems that the tag instrumentation is valid but the values are written in red, so I assume something is wrong with the targetPackage and name.

How can I get rid of this error and run a simple test on OneFragment using launchFragmentInContainer?

Bugdr0id
  • 2,962
  • 6
  • 35
  • 59

7 Answers7

45

The error was related to the way I did import the dependencies on Gradle.

Before:

androidTestImplementation("androidx.fragment:fragment-testing:1.1.0-beta01")
implementation("androidx.fragment:fragment-ktx:1.1.0-beta01")
androidTestImplementation("androidx.test:core:1.2.0")
androidTestImplementation("androidx.test:rules:1.2.0")
androidTestImplementation("androidx.test:runner:1.2.0")

After:

debugImplementation("androidx.fragment:fragment-testing:1.1.0-beta01")
debugImplementation("androidx.fragment:fragment-ktx:1.1.0-beta01")
debugImplementation("androidx.test:core:1.2.0")
debugImplementation("androidx.test:rules:1.2.0")
debugImplementation("androidx.test:runner:1.2.0")

Changed from androidTestImplementation to debugImplementation and it solved the issue. Compiling and running, and green test as result.

Mirjalal
  • 1,292
  • 1
  • 17
  • 40
Bugdr0id
  • 2,962
  • 6
  • 35
  • 59
  • 1
    It's good that you found solution, but https://developer.android.com/training/testing/set-up-project how come it's working for them? – Astha Garg Jun 13 '19 at 07:03
  • 9
    you can use debugImplementation so it doesn't get built in with your release builds – bsautner Aug 05 '19 at 16:57
  • 8
    set `debugImplementation` for `fragment-testing` should be enough, rest test dependencies can stay as `androidTestImplementation – Karol Kulbaka Mar 19 '20 at 17:40
  • 2
    why do we need to change ```debugImplementation``` ? – amlwin Aug 11 '20 at 05:31
  • Setting DebugImplementation just fo fragment-testing is OK (as mentioned in [Android docs](https://developer.android.com/training/basics/fragments/testing#configure)) – Vít Kapitola Sep 15 '20 at 13:44
  • 7
    That makes no sense. All Espresso tests go in `androidTestImplementation` – IgorGanapolsky Oct 21 '20 at 15:41
  • 1
    @IgorGanapolsky yeah it sounds weird, but Google itself mentioned exactly the same workaround here: https://developer.android.com/codelabs/advanced-android-kotlin-training-testing-test-doubles#7 see on top in Step1. Reason is, that `androidx.fragment` dependency is buggy and as it is usual for Google, it took them more than 2 years to fix. Reported bug from 2020 here: https://issuetracker.google.com/issues/128612536A And FINALLY, it looks like it is gonna be fixed in just few days with freshly released ` 1.6.0-alpha04` so let's celebrate :)) – qkx Dec 05 '22 at 05:20
12

Try to configure this way

debugImplementation('androidx.fragment:fragment-testing:1.1.0') {
        // exclude androidx.test:core while fragment_testing depends on 1.1.0
        exclude group: 'androidx.test', module: 'core'
    }
Levon Petrosyan
  • 8,815
  • 8
  • 54
  • 65
  • After changing androidTestImplementation to debugImplementation I got errors in my manifest that I don't have 'exported' field and it is needed in android 12 and above which I had it in my manifest and it was keep complaining, but this answer solved the problem. – Bita Mirshafiee Nov 23 '21 at 12:39
4

it works for me

def fragmentx_version = "1.1.0"
implementation "androidx.fragment:fragment:$fragmentx_version"
debugImplementation ("androidx.fragment:fragment-testing:$fragmentx_version"){
     exclude group: 'androidx.test', module: 'core'
}
debugImplementation 'androidx.test:core-ktx:1.2.0'

@Test
fun verifyMap() {
     FragmentScenario.launchInContainer(HomeFragment::class.java)

     onView(withId(R.id.map)).check(matches(isDisplayed()))
}

2

The accepted answer is (almost) correct - I will just explain why.

So first, you need to change androidTestImplementation to debugImplementation but only for these 2 dependencies below (not all of them):

androidx.fragment:fragment-testing
androidx.test:core

And the reason? The root cause is an old bug (since 2020 already) in FragmentScenario reported here.

Google itself in their own codelabs recommends to not use androidTestImplementation for fragment testing dependency, more details here:

https://developer.android.com/codelabs/advanced-android-kotlin-training-testing-test-doubles#7

Quoting the important part:

// Testing code should not be included in the main code.
// Once https://issuetracker.google.com/128612536 is fixed this can be fixed.

implementation "androidx.fragment:fragment-testing:$fragmentVersion"
implementation "androidx.test:core:$androidXTestCoreVersion"

Except ideally it should be debugImplementation and not implementation

qkx
  • 2,383
  • 5
  • 28
  • 50
1

I referred the test samples for Espresso and have used the following set of dependencies in app level build.gradle file

dependencies {
implementation fileTree(dir: 'libs', include: ['*.jar'])
implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version"
implementation 'androidx.appcompat:appcompat:' + rootProject.androidxCompatVersion
implementation 'androidx.core:core-ktx:' + rootProject.androidxCoreVersion
implementation 'androidx.fragment:fragment-ktx:' + rootProject.androidxFragmentVersion

// Ideally this would only be present in test scope (Adding this fixed the issue for me)
debugImplementation 'androidx.fragment:fragment-testing:' + rootProject.androidxFragmentVersion
debugImplementation 'androidx.test:core:' + rootProject.coreVersion

testImplementation 'junit:junit:4.12'
testImplementation 'org.robolectric:robolectric:' + rootProject.robolectricVersion
testImplementation 'androidx.test:core:' + rootProject.coreVersion
testImplementation 'androidx.test.ext:junit:' + rootProject.extJUnitVersion
testImplementation 'androidx.test.espresso:espresso-core:' + rootProject.espressoVersion
testAnnotationProcessor 'com.google.auto.service:auto-service:1.0-rc4'

androidTestImplementation 'androidx.test:core:' + rootProject.coreVersion
androidTestImplementation 'androidx.test.ext:junit:' + rootProject.extJUnitVersion
androidTestImplementation 'androidx.test:runner:' + rootProject.runnerVersion
androidTestImplementation 'androidx.test.espresso:espresso-core:' + rootProject.espressoVersion
androidTestImplementation 'androidx.fragment:fragment-testing:' + rootProject.androidxFragmentVersion
androidTestImplementation 'org.robolectric:annotations:' + rootProject.robolectricVersion     }

Within you project level build.gradle file

ext {
buildToolsVersion = "28.0.3"
androidxCoreVersion = "1.1.0-rc02"
androidxCompatVersion = "1.1.0-rc01"
androidxFragmentVersion = "1.1.0-rc01"
coreVersion = "1.3.0-alpha03"
extJUnitVersion = "1.1.2-alpha03"
runnerVersion = "1.3.0-alpha03"
rulesVersion = "1.3.0-alpha03"
espressoVersion = "3.3.0-alpha03"
robolectricVersion = "4.3.1"   }

Inside the isolated fragment test class

@RunWith(AndroidJUnit4::class)
@LooperMode(LooperMode.Mode.PAUSED)
class ExampleFragmentTest{
@Test
fun launchFragmentAndVerifyTheUI(){
   /* This is used to launch the fragment in an isolated environment ( This is essentially an empty activity that
   houses that fragment ) */
   launchFragmentInContainer<ExampleFragment>()
    // Now using Espresso to verify the fragment's UI, i.e textview and verifying that its getting displayed
    onView(withId(R.id.textView)).check(matches(withText("I am a fragment")))
}  }
Rakhi Dhavale
  • 1,196
  • 12
  • 19
0

I got the same error with HiltTestActivity.kt, because I insert the AndroidManifest.xml parallel to the activity file.

My fix: Move the AndroidManifest.xml to the java folder.

Homan Huang
  • 413
  • 5
  • 8
0

I also got the same error. But in my case, i forgot to add HiltTestActivity.kt into AndroidManifest.xml.

<activity android:name=".support.view.HiltTestActivity" />

And this is my launchFragmentToContainer function.

inline fun <reified T : Fragment> launchFragmentToContainer(
    fragmentArgs: Bundle? = null,
    themeResId: Int,
    fragmentFactory: FragmentFactory? = null,
    crossinline action: T.() -> Unit = {}
) {
    val mainActivityIntent = Intent.makeMainActivity(
        ComponentName(
            ApplicationProvider.getApplicationContext(),
            HiltTestActivity::class.java
        )
    ).putExtra(THEME_EXTRAS_BUNDLE_KEY, themeResId)
    ActivityScenario.launch<HiltTestActivity>(mainActivityIntent).onActivity { activity ->
        fragmentFactory?.let {
            activity.supportFragmentManager.fragmentFactory = it
        }
        val fragment = activity.supportFragmentManager.fragmentFactory.instantiate(
            checkNotNull(T::class.java.classLoader),
            T::class.java.name
        )
        fragment.arguments = fragmentArgs
        activity.supportFragmentManager.beginTransaction()
            .add(android.R.id.content, fragment, "")
            .commitNow()
        (fragment as T).action()
    }
}