2017-02-16 131 views
1

根據Espresso文檔,儀器測試應自動等待AsyncTasks完成。但它不起作用。我創建了這個簡單的測試用例:Espresso不等AsyncTask完成

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] 

正如你可以看到測試結束時,即使執行後臺方法之前。 我該如何讓測試等待呢?

回答

3

原來,咖啡確實等待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());,因爲它會導致咖啡等待的AsyncTask後臺操作來完成。

TestingActivity只是一個空的活動:

public class TestingActivity extends Activity { 

} 
-1

它按預期工作。由於您在doInBackground()內呼叫Thread.sleep(),因此它不會使用UI線程。將該睡眠代碼移至onPostExecute,它應該按預期工作。

+0

正如你可以按預期它不工作日誌消息看。測試完成後調用doInBackground()方法,並且甚至不調用onPostExecute()。在完成測試之前,Espresso應該等待後臺操作完成。這可以是Thread.sleep()可以模擬的任何長時間運行的任務。 – McFarlane

+0

@MFFarlane你是否按照我的建議去做? –

+0

我沒有,因爲這不會反映測試用例。想象一下,通過網絡操作取代Thread.sleep。你不能從onPostExecute運行這些。 – McFarlane