MockK报no answer found错误,Retrofit Single模拟单元测试失败求助
解决MockK中
no answer found的错误 这个错误的核心原因很明确:你错误地mock了要测试的LoginPresenter本身,而不是使用真实的Presenter实例并mock它的依赖项。MockK的mock对象默认不会执行真实的方法逻辑,当你调用presenter.login(loginRequest)时,MockK找不到这个方法的预设响应,就会抛出no answer found异常。
接下来一步步修正你的测试:
1. 使用真实的Presenter实例,而非mock它
我们要测试的是LoginPresenter的真实业务逻辑,所以应该创建它的真实实例,然后手动注入我们mock好的依赖(单元测试里不需要依赖注入框架,直接赋值即可)。
2. 修正依赖mock的匹配与行为
- 先修正Presenter代码里的笔误:
saveCookieAndContinue方法中调用了accountDelegator.getCustomer(),但你的Presenter注入的属性是delegator,这里需要改成delegator.getCustomer(),否则测试会因为找不到accountDelegator而报错。 - 确保
delegator.login()的参数匹配准确,或者用any()来匹配任意LoginRequest(如果不需要严格匹配参数的话)。 - 处理RxJava线程问题:单元测试中不能使用Android主线程调度器,需要通过
RxJavaPlugins替换成同步调度器,避免测试卡住或报错。
修正后的完整测试代码
import io.mockk.every import io.mockk.mockk import io.mockk.verify import io.reactivex.Single import io.reactivex.plugins.RxJavaPlugins import io.reactivex.schedulers.Schedulers import org.junit.Before import org.junit.Test import org.junit.After class LoginPresenterTest { private lateinit var presenter: LoginPresenter private val delegator = mockk<AccountDelegatorContract>() private val viewCallback = mockk<LoginContract.LoginViewCallBack>(relaxed = true) // relaxed=true避免未预设方法报错 private val cookieStore = mockk<PianoCookieStore>(relaxed = true) private val loginRequest = LoginRequest("hello@gmail.com", "password123") private val customerResponse = CustomerResponse("jon", "richy") @Before fun setup() { // 替换RxJava调度器为同步的trampoline,解决Android主线程依赖问题 RxJavaPlugins.setIoSchedulerHandler { Schedulers.trampoline() } RxJavaPlugins.setMainThreadSchedulerHandler { Schedulers.trampoline() } // 创建真实Presenter实例,手动注入mock依赖 presenter = LoginPresenter().apply { loginViewCallBack = viewCallback delegator = this@LoginPresenterTest.delegator cookieStorage = cookieStore } // 预设依赖的行为 every { delegator.login(any()) } returns Single.just(Response.success<Void>(null)) every { delegator.getCustomer() } returns Single.just(customerResponse) } @Test fun testLoginSuccessFlow() { // 执行测试方法 presenter.login(loginRequest) // 验证流程是否正确执行 verify { delegator.login(loginRequest) } verify { cookieStore.saveSessionCookies(any()) } verify { delegator.getCustomer() } verify { viewCallback.onLoginSuccess(customerResponse) } } @After fun tearDown() { // 恢复RxJava默认调度器,避免影响其他测试 RxJavaPlugins.reset() } }
关键说明
relaxed = true:给viewCallback和cookieStore加上这个参数,意味着它们的未预设方法会返回默认值(比如null、空列表等),避免因为一些无关方法调用而抛出异常。- RxJava调度器替换:必须在测试前替换,否则
AndroidSchedulers.mainThread()会在单元测试环境中抛出异常,因为没有Android主线程上下文。 - 验证逻辑:用
verify来确认依赖方法是否被正确调用,这是单元测试的核心,确保Presenter的流程符合预期。
额外注意点
如果你的Presenter构造函数是@Inject constructor(),请确保它是public的,否则无法在测试中直接实例化。如果是private的,建议调整构造函数可见性,或者用反射创建实例,但优先选择测试友好的构造方式。
内容的提问来源于stack exchange,提问作者Jono
相关产品推荐
相关产品推荐

