有没有一种方法可以模拟构建在片段内部的ViewModel?我试图在一个片段上运行一些测试,其中一个片段函数与ViewModel交互,我想运行测试函数并为ViewModel提供一个模拟结果。这有可能吗?
MyFragment
class MyFragment : Fragment() {
@Inject
lateinit var viewModel: MyViewModel
override fun onCreate(savedInstanceState: Bundle?) {
(requireActivity().application as MyApplication).appComponent.inject(this)
super.onCreate(savedInstanceState)
}
}
测试
@RunWith(RoboeltricTestRunner::) {
@Before
fun setup() {
FragmentScenario.Companion.launchIncontainer(MyFragment::class.java)
}
}
是的,只需标记您的ViewModel
open
,然后您就可以在它上面创建一个mock实现。
open class MyViewModel: ViewModel() {
fun myMethodINeedToMock() {
}
}
class MockMyViewModel: MyViewModel() {
override fun myMethodINeedToMock() {
// don't call super.myMethodINeedToMock()
}
}
因此,在测试时将MockMyViewModel
注册到DI框架中。
我想我会为其他正在努力寻找解决方案的人发布这篇文章。您将希望使用一个片段工厂,它依赖于ViewModel。将ViewModel注入到fragments构造函数中,可以轻松地模拟ViewModel。FragmentFactory需要完成几个步骤,但一旦完成了几个步骤,就不会那么复杂了。
- Fragment将ViewModel添加到构造函数中
class MyFragment(private val viewModel: ViewModel) : Fragment {
...
}
- FragmentFactory,允许片段在构造函数中具有依赖关系
class MyFragmentFactory(private val viewModel: MyViewModel) : FragmentFactory() {
override fun instantiate(classLoader: ClassLoader, className: String): Fragment {
return when(className) {
MyFirstFragment::class.java.name -> {
MyFragment(viewModel)
}
// You could use this factory for multiple Fragments.
MySecondFragment::class.java.name -> {
MySecondFragment(viewModel)
}
// You also don't have to pass the dependency
MyThirdFragment::class.java.name -> {
MyThirdFragment()
}
else -> super.instantiate(classLoader, className)
}
}
}
- 主活动
class MainActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
// Create your ViewModel
val viewModel = ViewModelProvider(this).get(MainViewModel::class.java)
// create the FragmentFactory and the viewModel dependency.
supportFragmentManager.fragmentFactory = MainFragmentFactory(viewModel)
// FragmentFactory needs to be created before super in an activity.
super.onCreate(savedInstanceState)
}
}
- 测试
@RunWith(RobolectricTestRunner::class)
class MyFragmentUnitTest {
@Before
fun setup() {
val viewModel: MainViewModel = mock(MyViewModel::class.java)
...
}
}