Espresso - 在 AsyncTask 期间截取屏幕截图

Espresso - Taking screenshot during an AsyncTask

我目前正在使用 Espresso 以编程方式截取 Android 应用程序的屏幕截图。我成功使用

android.support.test.runner.screenshot.Screenshot

问题是,给定以下假设 from official Espresso docs

  • The message queue is empty.
  • There are no instances of AsyncTask currently executing a task.
  • All developer-defined idling resources are idle.

By performing these checks, Espresso substantially increases the likelihood that only one UI action or assertion can occur at any given time. This capability gives you more reliable and dependable test results.

AsyncTask 为 运行 时,我无法执行任何测试。当我的 AsyncTask 为 运行 时,我需要截取一些屏幕截图,但无法理解有关如何执行此类任务的文档。 The most similar SO thread I found好像不行,不知道是不是因为AsyncTask速度太快,没法截图。

// Start the async task    
onView(withId(R.id.start_task_button)).perform(click());

// Then "press" the back button (in the ui thread of the app under test)
mActivityTestRule.runOnUiThread(new Runnable() {
    @Override
    public void run() {
        mScreenshotWatcher.captureScreenshot("screenshot1");
    }
});

有什么线索吗?这是正确的方法还是我应该在 AsyncTask 中实施 IdlingResource

谢谢 尼古拉

根据我对你问题的理解,你希望在 AsyncTask 正在进行时截取屏幕截图。

我创建了一个最小的 Android 应用程序来验证您的场景,但当使用来自 Espresso 的 click() 时它不起作用。问题在于,一旦 Espresso 执行了它的 click(),它就会在之后调用 loopMainThreadUntilIdle()。由于此时您的 AsyncTask 已经启动,UiControllerImpl#loopMainThreadUntilIdle() 中的循环已经 运行 一遍又一遍,直到 AsyncTask 完成。

克服这个问题的最简单方法是使用自定义 ViewMatcher 进行点击并立即返回。

MainActivity.java

public class MainActivity extends AppCompatActivity {
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        findViewById(R.id.test_edit_text).setOnClickListener(new View.OnClickListener() {
        @Override
        public void onClick(View v) {
            v.setVisibility(View.INVISIBLE);
            new AsyncTask<Object, Object, Object>() {
                @Override
                protected Object doInBackground(Object... objects) {
                    SystemClock.sleep(20000000);
                    return null;
                }

                @Override
                protected void onPostExecute(Object o) { 
                    findViewById(R.id.test_edit_text)
                    .setVisibility(View.VISIBLE);
                }
            }.execute();
        }});
    }
}

AndroidManifest.xml

<?xml version="1.0" encoding="utf-8"?>
<manifest package="com.question.Whosebug"
      xmlns:android="http://schemas.android.com/apk/res/android">
    <uses-permission android:name="android.permission.INTERNET"/>
    <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>

    <application
        android:allowBackup="true"
        android:icon="@mipmap/ic_launcher"
        android:label="@string/app_name"
        android:supportsRtl="true"
        android:theme="@style/AppTheme">
        <activity android:name=".MainActivity">
            <intent-filter>
                <action android:name="android.intent.action.MAIN"/>
                <category android:name="android.intent.category.LAUNCHER"/>
            </intent-filter>
        </activity>
    </application>
</manifest>

MainActivityTest.java

@RunWith(AndroidJUnit4.class)
public class ExampleInstrumentedTest {
    @Rule
    public ActivityTestRule<MainActivity> activityActivityTestRule = new ActivityTestRule<MainActivity>(MainActivity.class);
    @Test
    public void testTakeScreenshot() throws Exception {
        Espresso.onView(withId(R.id.test_edit_text)).check(matches(isDisplayed()));
        // use a custom ViewAction here because this call has be non-blocking                           
        Espresso.onView(withId(R.id.test_edit_text)).perform(new ViewAction() {
            @Override
            public Matcher<View> getConstraints() {
                return isDisplayingAtLeast(90);
            }
            @Override
            public String getDescription() {
                return "NonBlockingTap";
            }
            @Override
            public void perform(UiController uiController, View view) {
                view.performClick();
            }
        });
        ScreenCapture screenCapture = Screenshot.capture();
        screenCapture.setFormat(Bitmap.CompressFormat.PNG);
        screenCapture.setName("test.png");
        screenCapture.process(); 
        Espresso.onView(withId(R.id.test_edit_text)).check(matches(isDisplayed()));       
    }
}