Using Espresso idling resource with multiple activities

前端 未结 2 993
青春惊慌失措
青春惊慌失措 2021-02-06 02:24

I have a firstActivity that launches the secondActivity, where in the secondActivity I have a loading Dialog (not AsyncTask), and I need to make Espresso wait until the dialog d

相关标签:
2条回答
  • 2021-02-06 03:06

    I stumbled upon this question in my search for a similar answer. Using concepts from Stefano Dacchille's article on IdlingResources, I built the following idling resource that waits for a specific Activity to be active before firing. In my case, I know the dialog is showing when a fragment with a specific tag exists. This isn't the same as the OP's test, but the concepts should translate well.

    public class BusyWhenFragmentExistsInActivityIdlingResource implements IdlingResource {
        private FragmentActivity activity = null;
        private final String fragmentTag;
        private ResourceCallback resourceCallback;
        private boolean wasIdleLastTime = true; // Start off as idle
        private final String name;
        // Need this strong reference because ActivityLifecycleMonitorRegistry won't hold one
        private final ActivityLifecycleCallback activityLifecycleCallback;
    
        public BusyWhenFragmentExistsInActivityIdlingResource(
                final Class<? extends FragmentActivity> clazz,
                final String fragmentTag
        ){
            name = BusyWhenFragmentExistsInActivityIdlingResource.class.getSimpleName()+" "+clazz.getSimpleName();
            this.fragmentTag = fragmentTag;
            activityLifecycleCallback = new ActivityLifecycleCallback() {
                @Override
                public void onActivityLifecycleChanged(Activity activity, Stage stage) {
                    if (!FragmentActivity.class.isAssignableFrom(activity.getClass())) {
                        return;
                    }
                    FragmentActivity fragmentActivity = (FragmentActivity) activity;
                    if (!clazz.isAssignableFrom(fragmentActivity.getClass())) {
                        return;
                    }
                    switch (stage){
                        case RESUMED:
                            BusyWhenFragmentExistsInActivityIdlingResource.this.activity = fragmentActivity;
                            break;
                        case STOPPED:
                            BusyWhenFragmentExistsInActivityIdlingResource.this.activity = null;
                            break;
                    }
                }
            };
    
            ActivityLifecycleMonitorRegistry.getInstance()
                    .addLifecycleCallback(activityLifecycleCallback);
    
        }
        @Override
        public String getName() {
            return name;
        }
    
        @Override
        public boolean isIdleNow() {
            if (activity==null) {
                return wasIdleLastTime = true;
            }
            boolean isIdleThisTime = activity
                    .getSupportFragmentManager()
                    .findFragmentByTag(fragmentTag)==null;
    
            if (!wasIdleLastTime && isIdleThisTime && resourceCallback!=null){
                resourceCallback.onTransitionToIdle();
            }
            return wasIdleLastTime = isIdleThisTime;
        }
    
        @Override
        public void registerIdleTransitionCallback(ResourceCallback resourceCallback) {
            this.resourceCallback = resourceCallback;
        }
    }
    

    To use it, add something similar to this to your test:

    @Before
    public void setUp() throws Exception {
        registerIdlingResources(new BusyWhenFragmentExistsInActivityIdlingResource(
                SomeOtherActivity.class,
                BaseActivity.LOADING_DIALOG
        ));
    }
    
    0 讨论(0)
  • 2021-02-06 03:10

    There are a few problems here:

    1. Your isIdleNow() calls getCurrentActivity() which calls waitForIdleSync() and runTestOnUiThread(). isIdleNow Javadoc says: "Espresso will always call this method from the main thread, therefore it should be non-blocking and return immediately." So this won't work as is, but you could call getActivitiesInStage directly from isIdleNow.
    2. Your other issue is that you store the reference to ResourceCallback but never invoke onTransitionToIdle, also you should allow for the possibility of more than one ResourceCallback being registered and call onTransitionToIdle on all of the callbacks.

    You can do the following:

    1. Copy/Paste IdlingResource into your app as com.mycompany.IdlingResource.
    2. Then have your Activity implement that interface and make sure to call onTransitionToIdle when the dialog goes away and make sure isIdleNow returns false iff the dialog is showing.
    3. In your test code, write a "IdlingResourceAdapter" that wraps com.mycompany.IdlingResource and turns it into an Espresso IdlingResource and register that with Espresso.

    This will be simpler once this issue is implemented: https://code.google.com/p/android-test-kit/issues/detail?id=71

    0 讨论(0)
提交回复
热议问题