单元测试引用CookieManager的logout函数遇NoSuchMethodError的原因与解决
核心业务代码
应用的logout函数执行时会调用CookieManager.getInstance().removeAllCookies(null),核心代码如下:
fun logout(...) { showLoader(true) msgRepo.unregisterSendBirdHandlersAndPushToken( onSuccess = { clearUserData(...) // ... onLogout() }, onFailure = { clearUserData(...) // ... onLogout() } ) } /** * Helper to clear user data before logging user out */ private fun clearUserData(...) { // ... CookieManager.getInstance().removeAllCookies(null) }
测试用例示例
编写的调用logout的测试用例示例:
@Test fun `verify logout with success`() { // .. Other code HardLogoutHelper.logout(...) // ... }
报错信息
测试时触发如下错误:
'void android.webkit.CookieManager.removeAllCookies(android.webkit.ValueCallback)'
java.lang.NoSuchMethodError: 'void android.webkit.CookieManager.removeAllCookies(android.webkit.ValueCallback)'
at com.example.helpers.HardLogoutHelper.clearUserData(HardLogoutHelper.kt:86)
已尝试的方案
- 使用
@RunWith(RoboelectricTestRunner::class)运行测试 - 为CookieManager创建自定义Roboelectric Shadow,但问题仍未解决
错误原因
- API版本不匹配:
CookieManager.removeAllCookies(ValueCallback)是Android API 21(Android 5.0)才新增的方法,若你的测试环境(Roboelectric指定的SDK版本)低于API 21,就会出现找不到方法的错误。 - Shadow类未正确覆盖方法:Roboelectric自带的ShadowCookieManager可能未对该方法做适配,或者你自定义的Shadow类没有正确实现该方法的签名(比如参数类型不对、未指定minSdk)。
修复方案
方案1:指定Roboelectric测试的SDK版本为API 21+
在测试类上添加@Config注解,强制测试环境使用包含目标方法的SDK版本:
@RunWith(RoboelectricTestRunner::class) @Config(sdk = [Build.VERSION_CODES.LOLLIPOP]) class HardLogoutHelperTest { // 测试用例 }
方案2:修改业务代码做版本兼容
如果应用需要兼容API 21以下的设备,在clearUserData中加入版本判断,调用对应版本的方法:
private fun clearUserData(...) { // ... val cookieManager = CookieManager.getInstance() if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) { cookieManager.removeAllCookies(null) } else { @Suppress("DEPRECATION") cookieManager.removeAllCookie() // API 21以下的废弃方法,无回调参数 } }
方案3:正确实现自定义ShadowCookieManager
若坚持使用自定义Shadow,需确保Shadow类正确覆盖API 21+的方法,并指定minSdk:
@Implements(CookieManager.class) public class ShadowCustomCookieManager extends ShadowCookieManager { @Implementation(minSdk = Build.VERSION_CODES.LOLLIPOP) public void removeAllCookies(ValueCallback<Boolean> callback) { // 自定义实现逻辑,比如直接回调成功 if (callback != null) { callback.onReceiveValue(true); } } }
然后在测试类的@Config中指定使用该Shadow:
@RunWith(RoboelectricTestRunner::class) @Config( sdk = [Build.VERSION_CODES.LOLLIPOP], shadows = [ShadowCustomCookieManager::class] ) class HardLogoutHelperTest { // 测试用例 }
内容的提问来源于stack exchange,提问作者Orbit
相关产品推荐
相关产品推荐

