【问题标题】:Espresso does not wait for AsyncTask to finishEspresso 不等待 AsyncTask 完成
【发布时间】:2017-02-16 14:38:42
【问题描述】:

根据 Espresso 文档,仪器测试应自动等待 AsyncTasks 完成。但它不起作用。我创建了这个简单的测试用例:

package foo.bar;

import android.os.AsyncTask;
import android.support.test.annotation.UiThreadTest;
import android.support.test.filters.LargeTest;
import android.support.test.rule.UiThreadTestRule;
import android.support.test.runner.AndroidJUnit4;
import android.util.Log;

import org.junit.Rule;
import org.junit.Test;
import org.junit.runner.RunWith;

import static org.junit.Assert.assertEquals;

@RunWith(AndroidJUnit4.class)
@LargeTest
public class ExampleInstrumentedTest {

    private static final String TAG = "ExampleInstrumentedTest";

    @Rule public UiThreadTestRule uiThreadTestRule = new UiThreadTestRule();

    @Test
    @UiThreadTest
    public void testAsyncTask() throws Throwable {
        Log.d(TAG, "testAsyncTask entry");
        uiThreadTestRule.runOnUiThread(() -> new AsyncTask<String, Void, Integer>() {
            @Override
            protected Integer doInBackground(String... params) {
                Log.d(TAG, "doInBackground() called with: params = [" + params + "]");
                try {
                    Thread.sleep(2000);
                } catch (InterruptedException ignored) {
                }
                return params.length;
            }

            @Override
            protected void onPostExecute(Integer integer) {
                Log.d(TAG, "onPostExecute() called with: integer = [" + integer + "]");
                assertEquals(3, (int) integer);
                throw new RuntimeException("this should fail the test");
            }
        }.execute("One", "two", "three"));
        Log.d(TAG, "testAsyncTask end");
    }
}

返回 UI 线程时测试应该失败,但它总是成功。 这是测试的 logcat 输出:

I/TestRunner: started: testAsyncTask(foo.bar.ExampleInstrumentedTest)
D/ExampleInstrumentedTest: testAsyncTask entry
D/ExampleInstrumentedTest: testAsyncTask end
I/TestRunner: finished: testAsyncTask(foo.bar.ExampleInstrumentedTest)
D/ExampleInstrumentedTest: doInBackground() called with: params = [[Ljava.lang.String;@8da3e9]

正如您所见,测试甚至在后台方法执行之前就完成了。 我怎样才能让测试等待它?

【问题讨论】:

    标签: java android testing android-asynctask android-espresso


    【解决方案1】:

    事实证明,Espresso确实等待 AsyncTasks 完成但只有在存在视图交互时

    原因是 Espresso 在 UiController#loopMainThreadUntilIdle() 方法期间等待任务,该方法在每次视图交互时自动在幕后调用。因此,尽管我的测试不需要任何视图或活动,但我必须创建它们。

    这就是工作测试现在的样子:

    @RunWith(AndroidJUnit4.class)
    @LargeTest
    public class ExampleInstrumentedTest {
    
        private static final String TAG = "ExampleInstrumentedTest";
    
        @Rule public ActivityTestRule<TestingActivity> activityTestRule = new ActivityTestRule<>(
            TestingActivity.class, false, false);
    
        @Before
        public void setUp() throws Exception {
            activityTestRule.launchActivity(new Intent());
        }
    
        @Test
        public void testAsyncTask() throws Throwable {
            Log.d(TAG, "testAsyncTask entry");
    
            AsyncTask<String, Void, Integer> task = new AsyncTask<String, Void, Integer>() {
    
                @Override
                protected Integer doInBackground(String... params) {
                    Log.d(TAG, "doInBackground() called with: params = [" + params + "]");
                    try {
                        Thread.sleep(2000);
                    } catch (InterruptedException ignored) {
                    }
                    return params.length;
                }
    
                @Override
                protected void onPostExecute(Integer integer) {
                    Log.d(TAG, "onPostExecute() called with: integer = [" + integer + "]");
                    assertEquals(3, (int) integer);
                    throw new RuntimeException("this should fail the test");
                }
            };
            task.execute("One", "two", "three");
            Espresso.onView(withId(android.R.id.content)).perform(ViewActions.click());
    
            Log.d(TAG, "testAsyncTask end");
        }
    }
    

    最重要的新行是:Espresso.onView(withId(android.R.id.content)).perform(ViewActions.click());,因为它会导致 Espresso 等待 AsyncTask 后台操作完成。

    TestingActivity 只是一个空的 Activity:

    public class TestingActivity extends Activity {
    
    }
    

    【讨论】:

      【解决方案2】:

      您是否尝试过使用Espresso.onIdle()

      来自文档:

      循环主线程直到应用程序空闲。

      仅对不与任何 UI 元素交互但需要 Espresso 的主线程同步的测试调用此方法!此方法主要用于构建在 Espresso 之上的测试实用程序和框架。

      【讨论】:

        【解决方案3】:

        它按预期工作。由于您在 doInBackground() 内调用 Thread.sleep(),它不会使 UI 线程休眠。将该休眠代码移至onPostExecute,它应该可以按预期工作。

        【讨论】:

        • 从日志消息中可以看出,它没有按预期工作。测试完成后调用 doInBackground() 方法,甚至不调用 onPostExecute() 方法。 Espresso 应等待后台操作完成后再完成测试。这可以是任何可以由 Thread.sleep() 模拟的长时间运行的任务。
        • @McFarlane 你按照我的建议做了吗?
        • 我没有,因为这不会反映测试用例。想象一下 Thread.sleep 被一个网络操作所取代。你不能从 onPostExecute 运行这些。
        • @McFarlane 如果您这样做,您会看到它有效并得出结论 Espresso 没有在 UI 线程外等待空闲资源。下次不要盲目地投票,您可以尝试建议的答案,看看它是如何从那里开始的。
        • 我没有否决你,因为你的提议不起作用,而是因为它没有回答问题。引用 Espresso 文档:The centerpiece of Espresso is its ability to seamlessly synchronize all test operations with the application being tested. By default, Espresso waits for UI events in the current message queue to be handled and for default AsyncTasks to complete before it moves on to the next test operation. 因此,如果我的使用不计为 默认使用How can I make the test to wait for it? 您的建议消除了对任何我不需要的异步操作的需要。
        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2015-11-11
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2020-12-16
        • 1970-01-01
        相关资源
        最近更新 更多