首页 > 解决方案 > 如何测试从其他类方法内部获取值的方法

问题描述

每次我遇到 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;
        }

标签: androidmockitoretrofitandroid-testing

解决方案


TL;博士:

@Rule 
public InstantTaskExecutorRule InstantTaskExecutorRule = new InstantTaskExecutorRule();

我假设您要编写单元测试(在 JVM 上运行)而不是仪器测试(在 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 来模拟方法调用。

或者,您可以将测试作为 Instrumentation 测试执行(将其放在androidTest源集中)。然后它们在 Android 设备上执行。

在这种情况下LiveData,您可以通过更改LiveData发送方式来规避这种情况。谷歌为这种情况提供了一个 JUnit TestRule,你必须向你的build.gradleTestRule你的测试类添加一个工件

构建.gradle:

testImplementation 'androidx.arch.core:core-testing:2.1.0'

测试类:

@Rule 
public InstantTaskExecutorRule InstantTaskExecutorRule = new InstantTaskExecutorRule();

在旁注中:

  • 不要Retrofit在单元测试中进行网络或对真实 URL 的调用。最好将其指向baseUrl模拟服务器并使用OkHttp MockWebServer伪造您的网络响应
  • 如果你没有你想把它放在那里的updateUser方法。ViewModel因为这正是 a 的用例ViewModel
  • 如果你updateUser在 a 中有方法ViewModel,那么你不需要返回LiveData. data LiveData应该是你的一个实例变量,然后ViewModel你可以在你的Activityor中观察它Fragment
  • 您可能希望使用 android de-facto log 标准Timber而不是自定义的LogUtils.

推荐阅读