使用Mockito对Repository做单元测试返回NullPointerException求助
问题排查与解决方案
核心错误原因
- 测试对象混淆:你需要测试的是
RemoteDiscoverRepository的真实逻辑,错误地对真实测试对象remote的方法进行打桩,Mockito无法拦截真实对象的方法调用,导致remote.trendingMovie()执行真实逻辑时触发空指针 - 依赖未打桩:你注入的
retrofitServices是Mock对象,但没有对它的discover()方法做打桩,默认返回null,后续调用null的trendingMovieOfTheDay()方法直接触发空指针 - 冗余无效Mock:额外声明的
discoverRepository是完全无用的Mock实例,你最终调用它的方法不会执行任何真实逻辑,完全脱离测试目标
修正方案
调整测试逻辑:测试真实RemoteDiscoverRepository实例的逻辑,仅Mock它的依赖RetrofitServices和下层的DiscoverDao,对依赖的方法做合理打桩即可。修正后的测试代码如下:
@RunWith(MockitoJUnitRunner::class) class DiscoverRepositoryTest { @get:Rule var instantTaskExecutorRule = InstantTaskExecutorRule() @Mock private lateinit var retrofitServices: RetrofitServices // 新增Mock DiscoverDao实例 @Mock private lateinit var discoverDao: DiscoverDao private lateinit var remote : RemoteDiscoverRepository private val dummy = DiscoverDummy.getDiscover() @Before fun setup(){ remote = RemoteDiscoverRepository(retrofitServices) } @Test fun trendingMovieTest() = runBlocking { // 打桩依赖的返回值:retrofitServices.discover()返回mock的discoverDao `when`(retrofitServices.discover()).thenReturn(discoverDao) // 打桩discoverDao的方法返回构造好的成功响应 `when`(discoverDao.trendingMovieOfTheDay()).thenReturn(Response.success(dummy.data)) // 调用真实测试对象的方法 val trending = remote.trendingMovie() // 验证依赖方法被调用 verify(retrofitServices).discover() verify(discoverDao).trendingMovieOfTheDay() // 结果校验 assertNotNull(trending) assertEquals(dummy.data?.results?.size, trending.data?.results?.size) } }
额外优化建议
- 协程调度优化:你当前代码里写死了
Dispatchers.IO,建议将Dispatcher作为构造参数注入,单元测试时可以传入TestDispatcher,避免测试时的协程调度异常 - 依赖适配:如果你使用的Mockito版本对suspend方法打桩有兼容问题,可以引入
org.mockito.kotlin:mockito-kotlin依赖,它的API对Kotlin语法适配性更好
内容的提问来源于stack exchange,提问作者Rizki Rakasiwi
相关产品推荐
相关产品推荐

