如何测试内部从其他类方法获取值的方法

问题描述

我尝试了几种方法来模拟和监视值,并在每次出现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方法,则不需要返回LiveDatadata LiveData应该是ViewModel的实例变量,然后您可以在ActivityFragment中观察到。
  • 您可能想使用android de-facto日志标准Timber而不是自定义LogUtils