问题描述
我尝试了几种方法来模拟和监视值,并在每次出现nullPointerException或其他Mockito错误时都调用下面的方法。 当我初次接触Mockito和android本身时,请让我们知道如何为下面的方法编写AndroidTest案例,该案例也使用Retrofit API调用。 我正在尝试编写覆盖整个方法的代码。 预先感谢
public LiveData<BaseModel<Onboarding>> updateUser(Result item) {
final mutablelivedata<BaseModel<Onboarding>> data = new mutablelivedata<>();
final BaseModel<Onboarding> dataWrapper = new BaseModel<>();
Map<String,String> headers = WaApplication.getContext().getRequestHeaders();
String tenantId = WaApplication.getContext().getTenantId();
service.updateUser(tenantId,headers,item).enqueue(new Callback<UserOnboarding>() {
@Override
public void onResponse(Call<Onboarding> call,Response<Onboarding> response) {
dataWrapper.setData(response.body());
dataWrapper.setResponseCode(response.code());
data.setValue(dataWrapper);
LogUtils.d(TAG,"updateUser:HTTPS_ONBOARDING_API_ENDPOINT: "+ BuildConfig.HTTPS_ONBOARDING_API_ENDPOINT);
LogUtils.d("OnBoardingService onRes",new Gson().toJson(response.body()));
}
@Override
public void onFailure(Call<Onboarding> call,Throwable t) {
LogUtils.e(TAG,"OnBoardingService API Failed. Error - " + t.getMessage());
data.setValue(null);
}
});
return data;
}
解决方法
TL; DR:
@Rule
public InstantTaskExecutorRule InstantTaskExecutorRule = new InstantTaskExecutorRule();
我假设您要编写一个单元测试(在JVM上运行),而不是一个Instrumentation测试(在Android设备上运行)。
在单元测试中,您对data.setValue()的呼叫将导致:
java.lang.RuntimeException: Method getMainLooper in android.os.Looper not mocked. See http://g.co/androidstudio/not-mocked for details.
at android.os.Looper.getMainLooper(Looper.java)
为了能够在JVM的单元测试中使用Android类,请将android.jar
添加到类路径中。这个jar包含所有Android类,但没有实现。因此,如果执行其任何代码,它总是会引发上述异常。 Android方法调用的真正实现仅在Android设备上可用。
因此,一般而言,对于单元测试,您必须使用例如来模拟方法调用。 Mockito。
或者,您可以将测试作为工具测试执行(将其放入androidTest
源集中)。然后将它们在Android设备上执行。
但是对于LiveData
,可以通过更改LiveData
的分配方式来规避。 Google为此提供了一个JUnit TestRule,您必须在build.gradle
中添加一个工件,并在测试类中添加TestRule
build.gradle:
testImplementation 'androidx.arch.core:core-testing:2.1.0'
测试类:
@Rule
public InstantTaskExecutorRule InstantTaskExecutorRule = new InstantTaskExecutorRule();
旁注:
- 请勿在单元测试中进行网络连接或
Retrofit
调用真实URL。最好将baseUrl
指向模拟服务器,并使用例如OkHttp MockWebServer - 如果您的
updateUser
中没有ViewModel
方法,则要放在其中。因为这正是ViewModel
的用例。 - 如果
updateUser
中有ViewModel
方法,则不需要返回LiveData
。data
LiveData
应该是ViewModel
的实例变量,然后您可以在Activity
或Fragment
中观察到。 - 您可能想使用android de-facto日志标准Timber而不是自定义
LogUtils
。