Mockito本地单元测试需AVD运行才能通过的问题排查与解决
为什么本地运行测试失败,必须启动AVD?
核心原因大概率是测试的类型和目录配置不对,或者你的Presenter/测试代码依赖了Android框架类,导致本地Java环境无法正常执行测试:
- 测试目录放错了:Android项目有两个测试目录:
src/test/java:用于本地单元测试,完全基于JVM运行,不需要Android设备/模拟器,专门测试纯Java逻辑。src/androidTest/java:用于仪器化测试,必须在Android设备或模拟器上运行,依赖完整的Android框架环境。
如果你的测试类放在了androidTest目录,本地运行(不启动AVD)时,JUnit无法在纯JVM环境中执行这些测试,自然会出现Mock交互未捕获的错误;而启动AVD后,测试在Android环境中执行,才能正常验证交互逻辑。
- 依赖配置错误:如果JUnit和Mockito的依赖被声明为
androidTestImplementation,这些依赖只会被仪器化测试使用,本地单元测试无法加载到正确的库,导致Mock逻辑失效。 - Presenter依赖Android框架类:如果你的Presenter里直接引用了
Context、Activity或者其他Android SDK类,本地单元测试的纯JVM环境无法实例化这些类,会导致测试失败,只有在Android设备/模拟器的环境中才能正常运行。
如何正确本地运行这类无Android交互的MVP测试?
按以下步骤排查和修复:
1. 调整测试目录位置
把你的Presenter测试类移动到src/test/java目录下,确保它属于本地单元测试范畴。
2. 修正依赖配置
在Module级别的build.gradle文件中,确保JUnit和Mockito的依赖使用testImplementation:
dependencies { // 本地单元测试依赖 testImplementation 'junit:junit:4.12' testImplementation 'org.mockito:mockito-all:1.10.19' // 如果有仪器化测试需要的依赖,单独用androidTestImplementation // androidTestImplementation 'androidx.test.ext:junit:1.1.5' }
同步Gradle后,本地测试就能正确加载这些依赖库。
3. 剥离Presenter的Android依赖
检查你的Presenter代码,确保它只依赖MainContract.View接口(纯Java接口,无Android类引用),不直接持有Context、Activity等Android对象。如果之前有依赖,重构代码把Android相关操作都放到View层实现,Presenter只负责业务逻辑和调用View的方法。
比如,Presenter应该是这样的:
public class MyPresenter implements MainContract.Presenter { private MainContract.View mView; public MyPresenter(MainContract.View view) { mView = view; } @Override public void onButtonClicked() { mView.showSuccessMessage(); } }
这里的MainContract.View是纯Java接口,没有任何Android依赖,这样本地测试就能轻松Mock这个View接口。
4. 正确配置测试运行选项
在Android Studio中,右键点击测试类,选择"Run [TestClassName]",确保运行配置是Unit Test(而不是Android Instrumented Test)。如果之前的配置不对,可以在Run/Debug Configurations里删除旧的配置,重新生成。
验证测试
完成以上步骤后,再次运行测试,不需要启动AVD,测试应该能在本地JVM环境中执行,并且正确捕获Presenter对View的方法调用,验证MVP的交互逻辑。
内容的提问来源于stack exchange,提问作者Evoxx

