使用Mockito测试LoginViewModel出现NullPointerException问题求助
问题原因与解决方案
核心问题定位
- 问题1:测试类中
LoginViewModel字段被错误添加了@Mock注解
我们需要测试真实的ViewModel业务逻辑,不需要mock它本身,这个注解不仅多余,还可能和@Before里的手动实例化逻辑冲突。 - 问题2:系统邮箱正则类
Patterns.EMAIL_ADDRESS在本地JVM单元测试中为空android.util.Patterns是Android SDK提供的类,本地单元测试运行在JVM环境,没有Android运行时支持,该类的默认实现是空桩,调用Patterns.EMAIL_ADDRESS会直接返回null,调用matcher方法就会触发NullPointerException。
修复步骤
步骤1:清理测试类的错误注解
删掉viewModel字段上的@Mock注解,修改后测试类的字段声明部分如下:
@RunWith(MockitoJUnitRunner::class) class LoginViewModelTest { @Mock private lateinit var repository: LoginRepository // 此处移除@Mock注解,使用手动创建的真实实例 private lateinit var viewModel: LoginViewModel @Mock private lateinit var preferences: Preferences @Rule @JvmField val instantTaskExecutorRule = InstantTaskExecutorRule() val invalidEmail = "" val invalidPassword = "" val validEmail = "test@email.com" val validPassword = "test12345" // 其余逻辑保持不变 }
步骤2:解决Patterns.EMAIL_ADDRESS的依赖问题
有两种可选方案:
方案A:使用Robolectric提供Android运行时环境(推荐)
Robolectric可以在本地JVM上模拟Android运行环境,让系统类可以正常调用:
- 模块
build.gradle添加Robolectric依赖
testImplementation "org.robolectric:robolectric:4.9"
- 把测试类的
@RunWith注解改为@RunWith(RobolectricTestRunner::class)即可。
方案B:替换系统邮箱正则,不依赖Android SDK
如果不想引入Robolectric,可以直接把邮箱校验逻辑换成自定义正则,修改LoginViewModel的isEmailValid方法:
private fun isEmailValid(email: String): Boolean { // 自定义邮箱正则,替换系统的Patterns.EMAIL_ADDRESS val emailPattern = "^[A-Za-z0-9+_.-]+@[A-Za-z0-9.-]+\\.[A-Za-z]{2,}$" return Pattern.compile(emailPattern).matcher(email).matches() }
可选优化
你当前用空字符串作为非法邮箱,修复后可以补充更多场景,比如格式错误的邮箱(test@.com、test.com等),覆盖更多异常情况。
内容的提问来源于stack exchange,提问作者dazai
相关产品推荐
相关产品推荐

