Testing Fragment scenario (ch 9)

I’m trying to test whether a checkbox is checked.

The code is following:

@RunWith(JUnit4::class)
class CrimeDetailFragmentTest {

  private lateinit var scenario: FragmentScenario<CrimeDetailFragment>

  @Before
  fun setup() {
    scenario = launchFragment()
  }

  @After
  fun tearDown() {
    scenario.close()
  }


  @Test fun checkbox_updates_crime() {
    onView(withId(R.id.chbx_solved))
      .perform(click())

    scenario.onFragment {
      onView(withId(R.id.chbx_solved))
        .check(matches(isChecked()))
    }
  }
}

Right now the class fails to run on either the emulator or a physical device - the build continues indefinitely and the only hint of any problem is the error [ddms]: Exception during activity from Selector.

What is wrong with my code?

You’ve got two issues here:

  • Use launchFragmentInContainer instead of launchFragment when creating your scenario. If you want to test your UI within your Fragment you need to use that API. See: Test your fragments  |  Android Developers
  • Do not use scenario.onFragment {} when doing your check. That function is only needed if you need to call functions or access properties within the Fragment. You do not need it to perform Espresso validations. Pull that onView()... code out of that scenario.onFragment {} lambda expression and just invoke it the same way that you did when you clicked the checkbox.

I hope that helped.

I’ve changed the setup to launchFragmentInContainer().

Unfortunately, the same problem remains - the Gradle build doesn’t finish.

Is it possible the problem is because the fragment is declared in the XML and not in the KT class?

Edit: tried it with supportFragmentManager, that wasn’t the problem.

Just to make sure we are on the same page, this is what your code looks like after the changes:

@RunWith(JUnit4::class)
class CrimeDetailFragmentTest {

  private lateinit var scenario: FragmentScenario<CrimeDetailFragment>

  @Before
  fun setup() {
    scenario = launchFragmentInContainer() // new
  }

  @After
  fun tearDown() {
    scenario.close()
  }


  @Test fun checkbox_updates_crime() {
    onView(withId(R.id.chbx_solved))
      .perform(click())

    onView(withId(R.id.chbx_solved)) // new
      .check(matches(isChecked()))
  }
}

If so, what is logged out to the console when this fails?

Yes, that’s how the code looks like.

The Run tab then is stuck here indefinitely:

And the Build tab is stuck like this indefinitely:

Testing this on an M1 MBP, both emulator and a physical device.

Hmmmmm, that’s weird. Can you try running the tests from the command line? Try this command from within the project folder and let me know what output you get:

./gradlew connectedCheck --stacktrace

The whole command history:

[0] :arrow_forward: ./gradlew connectedCheck --stacktrace
Starting a Gradle Daemon, 1 stopped Daemon could not be reused, use --status for details

Task :app:compileDebugKotlin
w: /Users/USERNAME/Magic/Android/CriminalIntent/app/src/main/java/com/example/criminalintent/detail/CrimeDetailFragment.kt: (61, 69): Parameter ‘b’ is never used, could be renamed to _
<============-> 96% EXECUTING [38s]
:app:connectedDebugAndroidTest
IDLE
IDLE

And it gets stuck at this.

Hmmmmmmm. Is there any chance you still have the “Don’t keep Activities” developer option enabled? That might cause issues here. Also, when running the test, do you see your Fragment briefly flash on the device’s screen? Are there any crashes that you are seeing in Logcat?

I’m sorry this is being so tricky to debug, but this is pretty strange and I’m not quite sure what is happening just yet.

No, it’s disabled.

Can you share your project so I can test if it works on my HW.

I figured it out. The fragment testing dependency requires another dependency: debugImplementation "androidx.test:monitor:1.6.0".

4 Likes

Thanks for figuring this out and posting it here.
I was just in the very same situation because of the same missing dependency.