Mockito 2.1.0 Mock Fianl类的原理

从Mockito 2.1.0版本开始,通过配置自定义MockMaker可以支持对final类进行mock。具体做法是在资源目录下创建指定配置文件,启用InlineByteBuddyMockMaker来绕过类型检查并使用Objenesis生成动态代理。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

Mockito 从2.1.0后开始支持对final类型的mock,默认是未开启的,如果需要开启支持,需要在test的resource目录下新建mockito-extensions文件夹,并且在里面放一个名为org.mockito.plugins.MockMaker的文件,文件内容是mock-maker-inline。那么Mockitor是怎么实现对final类型的mock的呢?我们来看下官方提示的

https://static.javadoc.io/org.mockito/mockito-core/2.11.0/org/mockito/Mockito.html#39

之前的话,直接mock final类型会提示:

org.mockito.exceptions.base.MockitoException:
Cannot mock/spy class com.mockito.xxxClass
Mockito cannot mock/spy because :
 - final class

因为mockito做了校验。

mockito.mock静态方法,调用了MockitoCore类的mock方法,

MockSettingsImpl

MockUtil

SubclassByteBuddyMockMaker


然后如果启用了final支持后,通过这个类InlineByteBuddyMockMaker来实现isTypeMockable方法。只有

转而把final类型的部分去掉了,同时不支持原始类型的包装类


如果通过了校验,同样采用objenesis来创建类的实例

Instantiator采用的是ObjenesisInstantiator来实现的,如果是构造器,则用ConstructorInstantiator。

至于启用的文件及文件内容是由PluginRegistry定义加载的

定义的INLINE_ALIAS

loadPlugin读取路径的文件


正常类路径不存在插件时返回ByteBuddyMockMaker,否则返回自定义的。


总结一下就是,通过加载值得自定义的MockMaker来跳过校验,然后利用Objenesis来生成动态代理对象

帮我使用junit4和mockito编写单元测试,覆盖下面的代码 package com.st.engineeringmode.viewmodel; import android.util.Log; import androidx.lifecycle.MutableLiveData; import com.bird.STJni; import com.kotei.fwksdk.appapi.log.ILogApiListener; import com.kotei.fwksdk.appapi.log.KtLog; import com.kotei.fwksdk.appapi.log.LogImpl; import com.st.engineeringmode.app.EngineeringModeApplication; import com.st.engineeringmode.base.BaseViewModel; import com.st.engineeringmode.util.LogUtils; public class LogConfigViewModel extends BaseViewModel { public static final int LOG_COPY_TYPE_ALL = 0; public static final int LOG_COPY_TYPE_ANDROID = 1; public static final int LOG_COPY_TYPE_MCU = 2; public static final int LOG_COPY_TYPE_SPECIAL = 3; public MutableLiveData<Integer> progress = new MutableLiveData<>(0); /** * 1 成功 * 2 失败 * 3 清除中 * 4 清除开始(我这边提供的 回调内没有 该状态) */ public MutableLiveData<Integer> clearState = new MutableLiveData<>(0); /** * 1 * 1 2 成功 * 2 * 0 3 失败 0 0 * 3 * 0 4 中止 (log copy is aborted by user) * 4 * 2 1 导出中(log is to large, wait again) */ public MutableLiveData<Integer> exportState = new MutableLiveData<>(0); public MutableLiveData<Integer> changeState = new MutableLiveData<>(0); private LogImpl log = (LogImpl) KtLog.create(EngineeringModeApplication.getInstance()); public LogConfigViewModel() { log.registerCallback("com.st.engineeringmode", iLogApiListener); } public void exportLog() { LogUtils.i(TAG, "exportLog=============="); progress.setValue(1); try { log.copyLogToUpan(LOG_COPY_TYPE_ANDROID); int logLevel = log.getLogLevel(); LogUtils.i(TAG, "logLevel:" + logLevel); } catch (Exception e) { LogUtils.e(TAG, e); } } public void clearLog() { LogUtils.i(TAG, "clearLog=============="); clearState.postValue(4); log.clearLogData(); } public void changeBootAnimation() { Log.i(TAG, "changeBootAnimation: "); changeState.postValue(1); } private ILogApiListener iLogApiListener = new ILogApiListener() { /** * * @param i * @param i1 * 1 1 成功 * 0 0 失败 * 2 2 删除中(log is to large, wait again) */ @Override public void onClearLogDataStatus(int i, int i1) { LogUtils.i(TAG, "--==--:" + i + " " + i1); if (i == 1 && i1 == 1) { clearState.postValue(1); } else if (i == 0 && i1 == 0) { clearState.postValue(2); } else if (i == 2 && i1 == 2) { clearState.postValue(3); } } /** * * @param i * @param i1 * 1 2 成功 * 0 3 失败 * 0 4 中止 (log copy is aborted by user) * 2 1 导出中(log is to large, wait again) */ @Override public void onCopyLogToUpanStatus(int i, int i1) { LogUtils.i(TAG, "------:" + i + " " + i1); if (i == 1 && i1 == 2) { exportState.postValue(1); progress.postValue(100); } else if (i == 0 && i1 == 3) { exportState.postValue(2); progress.postValue(0); } else if (i == 0 && i1 == 0) { exportState.postValue(2); progress.postValue(0); } else if (i == 0 && i1 == 4) { exportState.postValue(3); progress.postValue(0); } else if (i == 2 && i1 == 1) { if (exportState.getValue() == null || exportState.getValue() == 4) { return; } exportState.postValue(4); progress.postValue(1); } } @Override public void onSendLogDataToRemoteStatus(int i, int i1) { LogUtils.i(TAG, "-++---:" + i + " " + i1); } }; public void changeUsbMode(boolean isChecked) { LogUtils.i(TAG, "isChecked:" + isChecked); STJni.getInstance(EngineeringModeApplication.getInstance()).setOTG(isChecked ? 1 : 0); } public boolean getUsbMode() { int otgState = STJni.getInstance(EngineeringModeApplication.getInstance()).getOTG(); return otgState == 1; } }
最新发布
08-07
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值