I recently had to add test coverage to a class that has a hard, transiant dependency on FragmentManager via FragmentStateViewPager and its use of fragment transaction internally. After stepping through the source I find it impossible to use Mokito to mock(), so I started looking for a way to use a real FragmentManager in my test. At first I thought I need to actually create an hosting Activity and write the test as an instrumentation test, however a fellow android engineer @heathborders gave me the hint to take a look at the approach FragmentScenario use, so I am going to document the approach I used here.
This is written from memory, without compiler help, so it probably won’t compile and won’t match your environment.
@RunWith(RobolectricRunner::class)
class MyTest {
internal class DummyFragment: Fragment()
private val fragmentScenario = FragmentScenario.launchInContainer(DummyFragment::class.java)
@Before
fun setUp() {
fragmentScenario.recreate()
fragmentScenario.onFragment { frag ->
val fragManager = frag.parentFragmentManager
// use fragManager in your test object setup
}
}
}
How does this work? FragmentScenario has a internal empty FragmentActivity that supplies the Fragments it hosts with a real FragmentManager, so by using a dummy empty Fragment we are able to make use of the FragmentManager instance. And bonus point of using FragmentScenario is you can control the lifecycle state by using moveToState() which can help recreate some hard-to-recreate situations in Fragment/Activity lifecycle.
Hope this article can save someone two nights of sleep.