【问题标题】:Android test method called after presenter executes retrofit call演示者执行改造调用后调用的 Android 测试方法
【发布时间】:2017-06-23 05:09:34
【问题描述】:

我正在使用 Mockito 测试我的视图,但我的测试失败了,因为应该在改造调用完成后调用一个方法。在完成改造调用后,如何模拟演示者调用谁的方法的视图?我想验证下面的unBlockUI() 是否已被调用。我的测试显示blockUI() 被调用,但unblockUI() 未被调用。

我收到一条失败消息

Wanted but not invoked:
view.unBlockUI();

在我的演示者中,我有方法

public void fetchResults(){ 

    view.blockUI();

    ResultsDataService resultsDataService = new ResultsDataService()

    resultsDataService.getAllResults(new Callback<Catalog>() {

            @Override
            public void onResponse(Call<Catalog> call, Response<Catalog> response) {
                view.unBlockUI();

            }

            @Override
            public void onFailure(Call<Catalog> call, Throwable t) {
                view.unBlockUI();               
                t.printStackTrace();
            }
        })
}

结果数据服务。

public class ResultsDataService {

    private final RestApi restApi;

    public CatalogDataService() {
    //here I have a class that builds the REST Service
        restApi = RestServiceBuilder.createService(RestApi.class);
    }

    public void getAllResults() {
        Call<Catalog> call = restApi.getAllResults();
        call.enqueue(callback);
    }
}

我的测试方法

@Test
public void shouldFetchAllResults_allOK() {
presenter.fetchResults();`

verify(view).blockUI();//This is called
verify(view).unBlockUI();//this is not called
}

【问题讨论】:

  • 你调用改造函数的方式将在后台执行,所以在你得到服务器的响应之前,解决方案是调用 call.execute() 应该在 asynctask 中,我想您正在使用 call.enqueue 调用 api
  • 但是我不想在主线程上执行调用
  • Android 不允许在主线程上进行任何网络操作,因此,如果您想在一些网络操作之后调用任何东西,而不是并行执行,请使用 asyncTask 类。将您的 retrofit.enqueue() 替换为 retrofit.execute()。现在在你的 asynctask 的 doInBackground() 和 onPostExecute、updateUI 中调用这个 retrofit.execute() 或调用任何你想在响应后调用的东西

标签: android mockito retrofit2 powermockito


【解决方案1】:

我认为一种可能的解决方案是模拟ResultsDataService 以在每次调用getAllResults 时调用任何回调的onResponse 方法。

不幸的是,您在fetchResults 中创建ResultsDataService 的方式让您很难做到这一点。这就是我们所说的紧耦合。您有一个严格依赖于ResultsDataService 的方法,没有机会更改它。因此,您无法从外部控制演示者。根据经验,每次您看到 new 运算符时,这都是紧密耦合的标志。

通常我们使用依赖注入来解决这个问题。您可以在代码中执行此操作的一种方法是简单地更改 fetchResults 方法以接收服务作为参数:

public void fetchResults(@NonNull ResultsDataService service) {
   // ...
}

可能看起来不多,但现在在测试中您可以通过配置的模拟,而在您的应用中您只需通过真实的服务。

现在在你的测试中说你会像这样配置一个模拟:

ResultDataService service = mock(ResultDataService.class);
doAnswer(new Answer() {
        @Override
        public Object answer(InvocationOnMock invocation) throws Throwable {
            Call call = (Call) invocation.getArgument(0);
            call.onResponse(call, <some response here>);
            return null;
        }
    }).when(service.getAllResults(any(Call.class)));    

您现在可以使用它来将其传递给您的演示者fetchResults

上面的模拟是做什么的?它将调用传入参数的onResponse 方法。所以基本上它会在你调用fetchResults 时立即调用onResponse 回调。在您的情况下,这将反过来调用unBlockUI

请注意,您可以执行类似的操作来测试onFailure。您还应该使ResultsDataService 成为一个接口,这样您的演示者不依赖于具体的实现,而只依赖于接口。这更加灵活。

希望这会有所帮助。请记住,这是一种方法,不是单一方法。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-09-27
    • 1970-01-01
    • 2021-09-28
    • 1970-01-01
    • 1970-01-01
    • 2016-10-20
    相关资源
    最近更新 更多