Vah*_*hid 15 android kotlin android-jetpack-compose dagger-hilt
所以我想测试我的 jetpack compose 项目。在 Android 开发站点上按照 [这些说明] 1运行仪器测试非常容易,但是当您将@HiltViewModel注入添加到组合中时,事情就会变得复杂。
我正在尝试使用具有 @Inject 构造函数的 ViewModel 测试一个非常简单的撰写屏幕。屏幕本身看起来像这样:
@Composable
fun LandingScreen() {
val loginViewModel: LoginViewModel = viewModel()
MyTheme {
Surface(color = MaterialTheme.colors.background) {
val user by loginViewModel.user.observeAsState()
if (user != null) {
MainScreen()
} else {
LoginScreen(loginViewModel)
}
}
}
}
Run Code Online (Sandbox Code Playgroud)
这是视图模型:
@HiltViewModel
class LoginViewModel @Inject constructor(private val userService: UserService) : ViewModel() {
val user = userService.loggedInUser.asLiveData()
}
Run Code Online (Sandbox Code Playgroud)
用户服务当然是由房间数据库支持的,loggedInUser 属性返回一个Flow.
事情在标准运行中按预期工作,但是当尝试在仪器测试中运行它时,它无法注入视图模型。
@HiltAndroidTest
class LandingScreenTest {
@get:Rule
var hiltRule = HiltAndroidRule(this)
@get:Rule
val composeTestRule = createComposeRule()
@Inject
lateinit var loginViewModel: LoginViewModel
@Before
fun init() {
hiltRule.inject()
}
@Test
fun MyTest() {
composeTestRule.setContent {
MyTheme {
LandingScreen()
}
}
composeTestRule.onNodeWithText("Welcome").assertIsDisplayed()
}
}
Run Code Online (Sandbox Code Playgroud)
禁止注入 @HiltViewModel 类,因为它无法正确创建 ViewModel 实例。相反,通过 Android API(例如 ViewModelProvider)访问 ViewModel。注入的ViewModel:com.example.viewmodels.LoginViewModel
如何使用 ViewModelProvider 而不是 @HiltViewModel 来实现这一点?
小智 6
Hilt 需要一个入口点来注入字段。在这种情况下,这可能是一个用 @AndroidEntryPoint 注释的 Activity。您可以使用 MainActivity 来实现这一点,但这意味着您必须向每个测试添加代码才能导航到所需的屏幕,这可能会很乏味,具体取决于您的应用程序的大小,并且如果您的项目是多模块,则这是不可行的并且您当前的测试文件无权访问MainActivity。相反,您可以创建一个单独的虚拟 Activity,其唯一目的是托管您的可组合项(在本例中为 LoginScreen)并使用 @AndroidEntryPoint 对其进行注释。确保将其放入调试目录中,这样它就不会随项目一起提供。然后您可以使用 createAndroidComposeRule<Activity>() 来引用该可组合项。您不需要直接注入 ViewModel,因此也可以删除该行。
最后你的测试文件应该是这样的:
@HiltAndroidTest
class LandingScreenTest {
@get:Rule(order = 0)
val hiltRule = HiltAndroidRule(this)
@get:Rule(order = 1)
val composeRule = createAndroidComposeRule<LoginTestActivity>()
@Before
fun init() {
hiltRule.inject()
}
@Test
fun MyTest() {
composeTestRule.onNodeWithText("Welcome").assertIsDisplayed()
}
}
Run Code Online (Sandbox Code Playgroud)
你的虚拟活动可能如下所示:
@AndroidEntryPoint
class LoginTestActivity : ComponentActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContent {
LoginScreen()
}
}
}
Run Code Online (Sandbox Code Playgroud)
调试目录将如下所示:带有虚拟活动的调试目录
是的,调试目录有自己的清单,您应该在其中添加虚拟活动。设置导出为 false。
小智 2
尝试做这样的事情:
@HiltAndroidTest
class LandingScreenTest {
@get:Rule
var hiltRule = HiltAndroidRule(this)
@get:Rule
val composeTestRule = createComposeRule()
// Remove this line @Inject
lateinit var loginViewModel: LoginViewModel
@Before
fun init() {
hiltRule.inject()
}
@Test
fun MyTest() {
composeTestRule.setContent {
loginViewModel= hiltViewModel() // Add this line
MyTheme {
LandingScreen()
}
}
composeTestRule.onNodeWithText("Welcome").assertIsDisplayed()
}
}
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
5059 次 |
| 最近记录: |