Тестирование Android AsyncTask со Средой тестирования Android

У меня есть очень простой пример реализации AsyncTask, и имею проблему в тестировании его с помощью Android платформа JUnit.

Это работает просто великолепно, когда я инстанцирую и выполняю его в нормальном приложении. Однако, когда это выполняется от любого из классов Среды тестирования Android (т.е. AndroidTestCase, ActivityUnitTestCase, ActivityInstrumentationTestCase2 и т.д.), это ведет себя странно:

  • Это выполняется doInBackground() метод правильно
  • Однако это не делает вызывает любой из его методов уведомления (onPostExecute(), onProgressUpdate(), и т.д.) - просто тихо игнорирует их, не показывая ошибок.

Это - очень простой пример AsyncTask:

package kroz.andcookbook.threads.asynctask;

import android.os.AsyncTask;
import android.util.Log;
import android.widget.ProgressBar;
import android.widget.Toast;

public class AsyncTaskDemo extends AsyncTask<Integer, Integer, String> {

AsyncTaskDemoActivity _parentActivity;
int _counter;
int _maxCount;

public AsyncTaskDemo(AsyncTaskDemoActivity asyncTaskDemoActivity) {
    _parentActivity = asyncTaskDemoActivity;
}

@Override
protected void onPreExecute() {
    super.onPreExecute();
    _parentActivity._progressBar.setVisibility(ProgressBar.VISIBLE);
    _parentActivity._progressBar.invalidate();
}

@Override
protected String doInBackground(Integer... params) {
    _maxCount = params[0];
    for (_counter = 0; _counter <= _maxCount; _counter++) {
        try {
            Thread.sleep(1000);
            publishProgress(_counter);
        } catch (InterruptedException e) {
            // Ignore           
        }
    }
}

@Override
protected void onProgressUpdate(Integer... values) {
    super.onProgressUpdate(values);
    int progress = values[0];
    String progressStr = "Counting " + progress + " out of " + _maxCount;
    _parentActivity._textView.setText(progressStr);
    _parentActivity._textView.invalidate();
}

@Override
protected void onPostExecute(String result) {
    super.onPostExecute(result);
    _parentActivity._progressBar.setVisibility(ProgressBar.INVISIBLE);
    _parentActivity._progressBar.invalidate();
}

@Override
protected void onCancelled() {
    super.onCancelled();
    _parentActivity._textView.setText("Request to cancel AsyncTask");
}

}

Это - тестовый сценарий. Здесь AsyncTaskDemoActivity является очень простое Действие, обеспечивающее UI для тестирования AsyncTask в режиме:

package kroz.andcookbook.test.threads.asynctask;
import java.util.concurrent.ExecutionException;
import kroz.andcookbook.R;
import kroz.andcookbook.threads.asynctask.AsyncTaskDemo;
import kroz.andcookbook.threads.asynctask.AsyncTaskDemoActivity;
import android.content.Intent;
import android.test.ActivityUnitTestCase;
import android.widget.Button;

public class AsyncTaskDemoTest2 extends ActivityUnitTestCase<AsyncTaskDemoActivity> {
AsyncTaskDemo _atask;
private Intent _startIntent;

public AsyncTaskDemoTest2() {
    super(AsyncTaskDemoActivity.class);
}

protected void setUp() throws Exception {
    super.setUp();
    _startIntent = new Intent(Intent.ACTION_MAIN);
}

protected void tearDown() throws Exception {
    super.tearDown();
}

public final void testExecute() {
    startActivity(_startIntent, null, null);
    Button btnStart = (Button) getActivity().findViewById(R.id.Button01);
    btnStart.performClick();
    assertNotNull(getActivity());
}

}

Весь этот код работает просто великолепно, кроме того, что AsyncTask не вызывает, это - методы уведомления при выполнении в Среде тестирования Android. Какие-либо идеи?

94
задан Rahul Sharma 15 January 2018 в 07:54
поделиться

1 ответ

Чтобы справиться с этим, нужно запустить любой код, который вызывает AsyncTask в runTestOnUiThread () :

public final void testExecute() {
    startActivity(_startIntent, null, null);
    runTestOnUiThread(new Runnable() {
        public void run() {
            Button btnStart = (Button) getActivity().findViewById(R.id.Button01);
            btnStart.performClick();
        }
    });
    assertNotNull(getActivity());
    // To wait for the AsyncTask to complete, you can safely call get() from the test thread
    getActivity()._myAsyncTask.get();
    assertTrue(asyncTaskRanCorrectly());
}

По умолчанию junit запускает тесты в отдельном потоке, а не в основном пользовательском интерфейсе приложения. В документации AsyncTask говорится, что экземпляр задачи и вызов execute () должны находиться в основном потоке пользовательского интерфейса; это потому, что AsyncTask зависит от Looper основного потока и MessageQueue для правильной работы своего внутреннего обработчика.

ПРИМЕЧАНИЕ:

Ранее я рекомендовал использовать @UiThreadTest в качестве декоратора в методе тестирования, чтобы заставить тест запускаться в основном потоке, но это не совсем подходит для тестирования AsyncTask, потому что пока ваш тестовый метод выполняется в основном потоке, сообщения не обрабатываются в основном MessageQueue, включая сообщения, которые AsyncTask отправляет о своем ходе, что приводит к зависанию вашего теста.

25
ответ дан 24 November 2019 в 06:00
поделиться
Другие вопросы по тегам:

Похожие вопросы: