presenter 执行 retrofit 调用后调用的 Android 测试方法

标签 android mockito retrofit2 powermockito

我正在使用 Mockito 来测试我的 View ,但是我的测试失败了,因为在改造调用完成后应该调用一个方法。在完成改造调用后,如何模拟演示者调用谁的方法的 View ?我想验证下面的 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
}

最佳答案

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

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

通常我们使用依赖注入(inject)来解决这个问题。您可以在代码中执行此操作的一种方法是简单地更改 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 成为一个接口(interface),这样您的演示者不依赖于具体的实现,而只依赖于接口(interface)。这要灵活得多。

希望这对您有所帮助。请记住,这是执行此操作的一种方式,不是唯一的方式。

关于presenter 执行 retrofit 调用后调用的 Android 测试方法,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/44713462/

相关文章:

android - 如何将图像(字节数组)从 JSON 显示到 imageView 中...工厂返回 null

java - 如何给Android系统导航栏添加按钮?

java - mockito anyList 给定大小

java - 如何在 SpringBootTest 中模拟 Spring 的 @Retryable 属性,例如 maxAttemps 和延迟

java - Android改造向Spring Boot发送put请求时出错?

android - 改造 2 第 1 行第 1 列路径的输入结束 $

java - Retrofit 2通过MS graph api发送邮件返回参数 'Message'的值为空

java - 错误 : Target id is not valid.

javascript - window.close() 在 android webview 中不起作用?

java - Mockito 如何仅模拟父类(super class)方法的调用