启用ProGuard后,使用Espresso IdlingResource的Instrumentation测试失败:报错「isIdleNow() is returning true, but a message ... was never sent」
我之前踩过完全一样的坑!Debug构建下测试跑起来行云流水,结果一开ProGuard打release包跑测试,直接弹出这个报错,当时头都大了😅
问题根源
其实就是ProGuard的“优化”搞的鬼——它会把那些它觉得“没用”的类、方法或者内部类给混淆甚至直接移除。而UriIdlingResource要正常工作,得依赖网络请求库(比如OkHttp、Volley)的回调接口、自身的内部构造,还有你项目里处理API请求的相关代码。一旦这些被ProGuard动了手脚,Espresso就没法准确跟踪网络请求的状态,最后就出现了“明明返回空闲,但消息没发送”的矛盾报错。
解决办法
给ProGuard加几条规则,把关键代码保护起来:
保留Espresso IdlingResource相关类
先把UriIdlingResource本身和它的Builder类保住,别让ProGuard动它们:-keep class androidx.test.espresso.idling.net.UriIdlingResource { *; } -keep class androidx.test.espresso.idling.net.UriIdlingResource$Builder { *; }根据你用的网络库加对应规则
- 如果是用OkHttp配合的话,还要保住OkHttp的拦截器和Espresso对应的IdlingResource实现:
-keep class androidx.test.espresso.idling.net.OkHttp3IdlingResource { *; } -keep interface okhttp3.Interceptor { *; } -keepclassmembers class * implements okhttp3.Interceptor { <init>(); } - 要是用Volley,就得保住Volley的请求队列监听相关类:
-keep class androidx.test.espresso.idling.net.VolleyIdlingResource { *; } -keep class com.android.volley.RequestQueue { *; } -keepclassmembers class com.android.volley.RequestQueue { public void add(com.android.volley.Request); }
- 如果是用OkHttp配合的话,还要保住OkHttp的拦截器和Espresso对应的IdlingResource实现:
保住你自己的网络请求代码
如果你的项目里有封装的API工具类(比如ApiClient),也要确保ProGuard没混淆它的方法,不然UriIdlingResource可能匹配不上请求的URI:-keep class com.yourpackage.your.ApiClient { *; } -keepclassmembers class com.yourpackage.your.ApiClient { public <methods>; }把
com.yourpackage.your换成你自己的包名就行。确保测试类的初始化代码不被移除
要是你的UriIdlingResource是在测试类的@Before方法里初始化的,得保住这些测试方法不被ProGuard优化掉:-keep class com.yourpackage.test.** { *; } -keepclassmembers class com.yourpackage.test.** { @org.junit.Before <methods>; @org.junit.Test <methods>; }
调试小技巧
如果加了规则还是不行,可以开启ProGuard的-printmapping mapping.txt选项,生成混淆映射文件,看看是不是还有相关类被重命名了;或者先临时加-dontobfuscate关闭混淆,如果测试能过,就肯定是混淆规则没加全,再针对性调整。
内容来源于stack exchange

