Robolectric单元测试调用Fragment内getString触发IllegalStateException问题
问题现象
使用Robolectric对Fragment做单元测试时,调用Fragment内部的getString()方法抛出IllegalStateException异常,错误堆栈如下:
Caused by: java.lang.IllegalStateException: Fragment SomeFragment{1df37025} (29efd1d0-77c1-4293-a0f6-b808c7559cf4)} not attached to a context. at androidx.fragment.app.Fragment.requireContext(Fragment.java:805) at androidx.fragment.app.Fragment.getResources(Fragment.java:869) at androidx.fragment.app.Fragment.getString(Fragment.java:891)
业务代码(SomeFragment)
public void someMethod() { getString(R.string.some_res) }
原测试代码
@Before fun setUp() { val activity = Robolectric.buildActivity(SomeActivity::class.java).create().get() fragment = SomeFragment() fragmentManager = activity.supportFragmentManager val fragmentTransaction: FragmentTransaction = fragmentManager.beginTransaction() fragmentTransaction.add(fragment, null) fragmentTransaction.commit() } @Test @Throws(Exception::class) fun someTest() { fragment.someMethod() }
异常原因
FragmentTransaction.commit()是异步执行逻辑,你在测试代码中调用完commit()后立即触发Fragment的方法,此时事务还未完成调度,Fragment没有完成和宿主Activity的绑定,无法获取到Context实例,调用getString()依赖Context拿资源自然会报错。
修复方案
方案1:立即执行待处理的Fragment事务
在commit()调用后新增一行fragmentManager.executePendingTransactions(),强制主线程立即执行所有待处理的Fragment事务,确保Fragment完成attach后再执行测试逻辑,改动最小,无需调整现有测试结构。
修改后的测试代码如下:
@Before fun setUp() { val activity = Robolectric.buildActivity(SomeActivity::class.java).create().get() fragment = SomeFragment() fragmentManager = activity.supportFragmentManager val fragmentTransaction: FragmentTransaction = fragmentManager.beginTransaction() fragmentTransaction.add(fragment, null) fragmentTransaction.commit() // 新增这行 fragmentManager.executePendingTransactions() } @Test @Throws(Exception::class) fun someTest() { fragment.someMethod() }
方案2:使用官方推荐的FragmentScenario测试
AndroidX测试库提供的FragmentScenario是官方推荐的Fragment测试组件,会自动处理Fragment的生命周期和事务调度,不需要手动管理Activity和Fragment事务,代码更简洁可靠:
@Before fun setUp() { // 直接启动目标Fragment,自动完成attach逻辑 scenario = FragmentScenario.launchInContainer(SomeFragment::class.java) } @Test fun someTest() { scenario.onFragment { fragment -> fragment.someMethod() } }
需要提前在build.gradle中引入Fragment测试依赖:
dependencies { debugImplementation "androidx.fragment:fragment-testing:1.5.7" }
内容的提问来源于stack exchange,提问作者PhantomThief
相关产品推荐
相关产品推荐

