Espresso自动化测试(十一) - IdlingResource

Espresso测试有个很强大的地方是它在多个测试操作中是线程安全的。Espresso会等待当前进程的消息队列中的UI事件,并且在任何一个测试操作中会等待其中的AsyncTask结束才会执行下一个测试。这能够解决程序中大部分的线程同步问题。然而实际中,有许多的应用后台的操作都是使用自定义的服务去创建以及管理线程的。这个时候Espresso就无法做到同步了,那么有办法来解决这个问题吗?有的。可以通过IdlingResource来同步你的UI事件。

介绍

IdlingResource 它是一个简单的接口:
它代表了被测应用程序的资源,这个资源在测试执行时可以在后台异步工作。
接口定义了三个方法:

  • getName():必须返回代表idling resource的非空字符串;
  • isIdleNow():返回当前idlingresource的idle状态。如果返回true,onTransitionToIdle()上注册的ResourceCallback必须必须在之前已经调用;
  • registerIdleTransitionCallback:通常此方法用于存储对回调的引用来通知idle状态的变化。

下来直接说下测试过程中遇到的问题以及如何处理的吧。

问题: 点击界面某个按钮后,新出现的页面会存在一个progressDialogFragment进行网络的请求数据,直到网络异常后者请求成功才会消失

其实这个时候如何不做任何处理的话,很明显,Espresso在点击按钮后的其他操作都会失败,它肯定会报错说NoViewsMatching,所以我们需要自定义一个IdlingResource

public class ProgressFramentIdlingResource implements IdlingResource {

    private FragmentManager fragmentManager;
    private ResourceCallback resourceCallback;

    public ProgressFramentIdlingResource(FragmentManager fg) {
        fragmentManager = fg;
    }

    @Override
    public String getName() {
        return ProgressFramentIdlingResource.class.getName();
    }

    @Override
    public boolean isIdleNow() {
        //通过当前页面的fragment 是否存在以及可见,来判断。
        for (Fragment fragment:fragmentManager.getFragments()) {
            if(fragment != null && fragment.isVisible()) {
                resourceCallback.onTransitionToIdle();
                return false;
            }

        }

        return true;
    }

    @Override
    public void registerIdleTransitionCallback(ResourceCallback callback) {
        resourceCallback = callback;
    }
}

上面的方法是没问题的,但是问题来了,如何才能够获取到framgentManager呢。正常情况下我们只是需要activity.getSupportFragmentManager就可以解决,但是我们在Espresso中获取到的activity的对象却是上一个界面的对象,所以我们还得去有方法能够获取到当前的Acitivity。还是伟大的google帮忙了。

public Activity getActivityInstance(){
        try {
            testRule.runOnUiThread(new Runnable() {
                public void run() {
                    Collection<Activity> resumedActivities = ActivityLifecycleMonitorRegistry.getInstance().getActivitiesInStage(Stage.RESUMED);
                    for (Activity act: resumedActivities){
                        Log.d("Your current activity: ", act.getClass().getName());
                        currentActivity = act;
                        break;
                    }
                }
            });
        } catch (Throwable throwable) {
            throwable.printStackTrace();
        }

        return currentActivity;
 }

上面的方法就解决了获取当前Activity的问题了。

好了问题就这么解决了。下来我们只需要如此做。

IdlingResource idlingResource = new ProgressFramentIdlingResource(((UpdateSubjectActivity)getActivityInstance()).getSupportFragmentManager());
Espresso.registerIdlingResources(idlingResource);
****
Espresso.unregisterIdlingResources(idlingResource);

results matching ""

    No results matching ""