等待任务的Espresso空闲资源在onCreate

时间:2017-11-11 10:13:19

标签: java android android-espresso

我尝试使用Espresso IdlingResource等待Activity.onCreate中启动的后台任务。

我看到了类似问题herethere,但建议的解决方案对我来说并不适用。

我在waitForIdle(long timeout)中添加了一个Activity方法,我从我的@Before方法中调用了这种方法,这种方法有效,但在应用程序代码中有点侵入性,IdlingResource是就是为了这个目的。

根据给定的链接,我了解@BeforeActivity.onCreate后调用,然后我们注册IdlingResource太晚了。

我的IdlingResource需要Activity个实例来确定它是否空闲。使用ActivityTestRule.beforeActivityLaunched只允许我创建一个"空" IdlingResource(此时getActivity()null)并注册。然后在@Before我将Activity设置为我的IdlingResource,但Espresso仍然没有等待它。 isIdleNow甚至没有被调用。

(我并不热衷于为此目的覆盖测试运行器的想法)

以下是用于测试的片段:

MainActivity

public class MainActivity extends AppCompatActivity
{
  private Object mIdleMonitor = new Object();
  private boolean mIdle;

  private TextView mHello;
  private View mProgress;

  @Override
  protected void onCreate(Bundle savedInstanceState)
  {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);

    mHello = findViewById(R.id.main_hello);
    mProgress = findViewById(R.id.main_progress);

    toggleWorkingState(true);

    new Thread(new Runnable()
    {
      @Override
      public void run()
      {
        SystemClock.sleep(5000);
        runOnUiThread(new Runnable()
        {
          @Override
          public void run()
          {
            mHello.setText(R.string.main_hello_label);
            toggleWorkingState(false);
          }
        });
      }
    }).start();
  }

  @UiThread
  private void toggleWorkingState(boolean working)
  {
    mProgress.setVisibility(working ? View.VISIBLE : View.GONE);
    synchronized(mIdleMonitor)
    {
      mIdle = !working;
      mIdleMonitor.notify();
    }
  }

  public boolean isIdle()
  {
    synchronized(mIdleMonitor)
    {
      return mIdle;
    }
  }

  public void waitForIdle(long timeout)
  {
    long end = System.currentTimeMillis() + timeout;
    synchronized(mIdleMonitor)
    {
      while(!mIdle && System.currentTimeMillis() < end)
      {
        try
        {
          mIdleMonitor.wait(timeout);
        }
        catch(InterruptedException e)
        {
          break;
        }
      }
    }
  }
}

MainActivityIdlingResource

public class MainActivityIdlingResource implements IdlingResource
{

  private static int ID;
  private final int mId;

  private WeakReference<MainActivity> mObservable;

  @Nullable
  private ResourceCallback mCallback;

  private boolean mWasIdle = false;

  public MainActivityIdlingResource()
  {
    mId = ++ID;
  }

  public void setActivity(MainActivity observable)
  {
    mObservable = new WeakReference<>(observable);
  }

  @Override
  public String getName()
  {
    return MainActivityIdlingResource.class.getSimpleName() + "#" + mId;
  }

  @Override
  public boolean isIdleNow()
  {
    MainActivity observable = mObservable == null ? null : mObservable.get();
    boolean isIdle = observable != null && observable.isIdle();
    if (!mWasIdle && isIdle && mCallback != null)
    {
      mCallback.onTransitionToIdle();
    }
    mWasIdle = isIdle;
    return isIdle;
  }

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

MainActivityTest

@RunWith(AndroidJUnit4.class)
public class MainActivityTest
{

  private IdlingRegistry mIdlingRegistry = IdlingRegistry.getInstance();

  @Rule
  public ActivityTestRule<MainActivity> mActivityRule = new ActivityTestRule<MainActivity>(MainActivity.class)
  {
    @Override
    protected void beforeActivityLaunched()
    {
      super.beforeActivityLaunched();
      mIdlingResource = new MainActivityIdlingResource();
      mIdlingRegistry.register(mIdlingResource);
    }

    @Override
    protected void afterActivityFinished()
    {
      super.afterActivityFinished();
      if (mIdlingResource != null)
      {
        mIdlingRegistry.unregister(mIdlingResource);
      }
    }
  };

  private MainActivity mActivity;

  private MainActivityIdlingResource mIdlingResource;

  /**
   * Source: https://stackoverflow.com/a/37864603/2551689
   */
  public static ViewAction replaceProgressBarDrawable()
  {
    return actionWithAssertions(new ViewAction()
    {
      @Override
      public Matcher<View> getConstraints()
      {
        return isAssignableFrom(ProgressBar.class);
      }

      @Override
      public String getDescription()
      {
        return "replace the ProgressBar drawable";
      }

      @Override
      public void perform(final UiController uiController, final View view)
      {
        // Replace the indeterminate drawable with a static red ColorDrawable
        ProgressBar progressBar = (ProgressBar) view;
        progressBar.setIndeterminateDrawable(new ColorDrawable(0xffff0000));
        uiController.loopMainThreadUntilIdle();
      }
    });
  }

  @Before
  public void setUp()
  {
    mActivity = mActivityRule.getActivity();
    mIdlingResource.setActivity(mActivity);
    // using this watcher, UiController.loopMainThreadUntilIdle() fixes the idle issue, don't understand why nor if it's mandatory
    // onView(withId(R.id.main_progress)).perform(replaceProgressBarDrawable());
    // using mActivity.waitForIdle(6000); do the job but is not the expected solution
  }

  @Test
  public void test_idle_state()
  {
    assertTrue(mActivity.isIdle());
    onView(withId(R.id.main_progress)).check(matches(not(isDisplayed())));
    onView(withText(R.string.main_hello_label)).check(matches(isDisplayed()));
  }
}

0 个答案:

没有答案