在空闲资源繁忙时测试UI

时间:2016-10-14 12:31:39

标签: android rx-java android-espresso android-testing ui-testing

我是Android测试新手,我遇到了问题。我正在使用RxJava并测试我正在使用IdlingResource的UI。当空闲资源繁忙时,我无法测试UI。

例如:我有一个按钮。 onClick我正在做一个请求。请求按钮禁用时。请求后按钮处于启用状态。我想测试以下3个步骤:

  1. 请求前启用按钮
  2. 请求(onCLick)时按钮被禁用
  3. 请求结束并返回响应消息时启用按钮
  4. 如果你能在这个问题上帮助我,我会非常高兴...

    如果您需要有关我的问题的更多信息,请告诉我。我会编辑我的帖子

2 个答案:

答案 0 :(得分:2)

据我了解,您正在尝试测试您的用户界面。如果是这样,请确保您以正确的方式执行:

1)。您没有执行 REAL 请求。

请注意,在类似情况下,您的测试必须始终具有 相同的行为 。换句话说,它必须提供 相同的结果 ,您传递相同的输入参数。
您现在的输入参数:
  1.1)。在请求之前启用按钮
  1.2)。请求期间禁用按钮
  1.3)。请求后启用按钮

从这个列表中可以看出,您不需要做真正的请求。对你来说无关紧要,什么服务器会回复你(错误或成功)。你甚至不需要服务器。所有你需要的东西,只是“东西”,就像真正的服务器一样。换句话说,您必须模拟您的API客户端。

我想你正在使用改造。如果不是,则必须为客户端创建interface包装器。如果您正在使用改造,则只需要模拟interface

我们假设你有下一个interface

public interface ApiClient{
    @GET("/items")
    Observable<MyResponse> doSomeRequest();
}

您通常如何创建API客户端:

Retrofit retrofit = new Retrofit.Builder()
    .baseUrl("https://api.github.com/")
    .build();

ApiClient service = retrofit.create(ApiClient.class);

你应该如何在测试中做到这一点:

import static org.mockito.Mockito.*;

并且在测试方法中:

ApiClient apiMock = mock(ApiClient.class);
when(apiMock.doSomeRequest())
                .thenReturn(Observable.just(fakeResponse));

ApiClient apiMock = mock(ApiClient.class);
when(apiMock.doSomeRequest())
                .thenReturn(Observable.defer(new Func0<Observable<MyResponse>>() {
                        @Override
                        public Observable<MyResponse> call() {
                            try{
                                Thread.sleep(2 * 1000) //2 seconds
                            }catch(Exception e){
                                return Observable.error(e);
                            }
                            return Observable.just(fakeResponse);
                        }
                    }));

P.S。默认情况下,Retrofit会将.subscribeOn(Schedulers.io())添加到所有Observable。这个模拟对象不会这样做。因此,请不要忘记在代码中添加.subscribeOn(Schedulers.io()),或将其应用于Observable.defer(...)的结果。 在上面的代码中,它将如下所示:

when(apiMock.doSomeRequest())
     .thenReturn(Observable.defer(...).subscribeOn(Schedulers.io()));

您应该将apiMock传递给您尝试测试的Activity / Fragment
怎么做? 请参阅#2

2)。使用DI(依赖注入)

我不会写很多关于它的事 我建议您阅读http://google.github.io/dagger/

上的文档

尤其是,如何组织项目,何时可以使用真正的实现进行生产,以及模拟测试实现:

http://google.github.io/dagger/testing.html

换句话说,当您要构建应用程序以供使用时,您提供真正的依赖项(在您的情况下,它将是ApiClient的真实实现),并且当您要测试某些UI或业务逻辑,您传递模拟依赖项,它们具有您在测试之前指定的行为。

这就是全部,我想告诉你的。希望这有帮助,如果您有任何其他问题,请告诉我。

答案 1 :(得分:1)

Alexander's answer的小补充。我会使用Subject作为“模拟”api。这允许您控制执行。

//setup your test 
Subject<Response,Response> stubResponse = AsyncSubject.create();
ApiClient apiMock = mock(ApiClient.class);
when(apiMock.doSomeRequest()).thenReturn(stubResponse.asObservable());
//check first condition that button is enabled before executing action
//click on button
//test your second condition that button is disabled while waiting for response
stubResponse.onNext(fakeResponse); //return fake response
stubResponse.onCompleted();
//test your third condition that button is enabled when you get response back

备注。切勿在测试中使用sleep。它会减慢你的测试速度并增加瑕疵感。