Синхронизация Android Espresso с пользовательским ресурсом

Я хочу использовать Espresso для тестирования веб-вызовов. Я сделал небольшое тестовое приложение, чтобы посмотреть, смогу ли я заставить его работать без использования AsyncTask. После получения данных TextView сообщает пользователю, был ли вызов успешным или нет. Я делаю веб-вызов в новой теме.

В своем тесте я пытался выполнить AdvancedSynchronizationTest в качестве шаблона, заставляющего тест ожидать выполнения веб-запроса. Однако моя реализация, похоже, не работает. Насколько я понимаю, метод, который я переопределяю, заканчивается до того, как обратный вызов возвращается к основному действию. Если это так, я перезаписываю неправильный класс. Я также пытался переопределить сам runnable (см. пример ниже) и даже изменил обновление пользовательского интерфейса, просто установив логическое значение, но без другого результата. Очевидно, Espresso не нравится, когда я использую другой поток, но почему он не понимает, что должен дождаться завершения потока? Какой была бы альтернатива без использования AsyncTask?

Весь проект можно увидеть здесь: https://github.com/bqmackay/EspressoCustomThreadingResourceExample.

Вот рассматриваемый код:

ГлавнаяАктивностьТест

public class MainActivityTest extends ActivityInstrumentationTestCase2<MainActivity> {
...
    @Override
    protected void setUp() throws Exception {
        super.setUp();
        getActivity();

        Runnable runnable = getActivity().getDownloadHelper().getWebCallRunnable();
        CountingIdlingResource countingIdlingResource = new CountingIdlingResource("WebCallRunnableCall");
        getActivity().getDownloadHelper().setWebCallRunnable(new DecoratedWebCallRunnable(runnable, countingIdlingResource));
        registerIdlingResources(countingIdlingResource);
    }

    public void testThreadRetrieval() throws Exception {
        onView(withText("Thread")).perform(click());
        assertTrue(getActivity().isDidThreadReturn());
        //onView(withText("Thread Retrieved")).check(matches(isDisplayed()));
    }

    private class DecoratedWebCallRunnable implements Runnable {

        private final Runnable realRunnable;
        private final CountingIdlingResource countingIdlingResource;

        private DecoratedWebCallRunnable(Runnable realRunnable, CountingIdlingResource countingIdlingResource) {
            this.realRunnable = realRunnable;
            this.countingIdlingResource = countingIdlingResource;
        }

        @Override
        public void run() {
            countingIdlingResource.increment();
            try {
                realRunnable.run();
            } finally {
                countingIdlingResource.decrement();
            }
        }
    }

DownloadHelper

public class DownloadHelper {
    private Runnable webCallRunnable;

    private Runnable createWebCallRunnable() {
        return new Runnable() {
        @Override
        public void run() {
            HttpClient httpclient = new DefaultHttpClient();
            HttpResponse response = null;
            try {

                response = httpclient.execute(new HttpGet("http://whoismyrepresentative.com/getall_mems.php?zip=84020"));
                StatusLine statusLine = response.getStatusLine();
                if(statusLine.getStatusCode() == HttpStatus.SC_OK){
                    ByteArrayOutputStream out = new ByteArrayOutputStream();
                    response.getEntity().writeTo(out);
                    out.close();
                    repsCallbackInterface.onRepsThreadReceived(true);
                } else{
                    //Closes the connection.
                    response.getEntity().getContent().close();
                    repsCallbackInterface.onRepsThreadReceived(false);
                    throw new IOException(statusLine.getReasonPhrase());
                }
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
        };
    }
}

Основная деятельность

public class MainActivity extends Activity implements RepsCallbackInterface {
    ....
    @Override
    public void onRepsThreadReceived(final boolean didReceive) {
        setDidThreadReturn(true);
        runOnUiThread(new Runnable() {
            @Override
            public void run() {
                threadText.setText(didReceive ? "Thread Retrieved" : "Thread Failed");
            }
        });
    }
}

person Maxwell    schedule 27.04.2014    source источник


Ответы (1)


На самом деле вы не задали здесь вопрос, поэтому я предполагаю, что вопрос в том, почему эта настройка не работает должным образом.

Есть (как минимум) две причины:

  1. Утверждение assertTrue(getActivity().isDidThreadReturn());in testThreadRetrieval() вообще не ждет завершения IdlingResources. Только ViewInteraction.check() и ViewInteraction.perform() знают о них и проверят IdlingResources перед попыткой применить ViewAssertion или ViewAction.

  2. Даже если вместо этого применить закомментированную строку после assertTrue(), это не сработает, потому что инструментальный поток независим и не ждет запуска нового потока, созданного в getReps(), поэтому проверка IdlingResources может и произойдет до того, как CountingIdlingResource увеличивается.

Если по какой-либо причине вы действительно не хотите использовать AsyncTask, вы все равно можете извлечь выгоду из Espresso, наблюдающего за пулом потоков AsynTask с помощью его исполнителя. Поэтому вместо того, чтобы запускать отдельный поток, просто отправьте Runnable в AsyncTask.THREAD_POOL_EXECUTOR.

person haffax    schedule 27.04.2014
comment
пожалуйста, если у вас есть какой-либо проект в студии Android (gradle proj.) с работающим ресурсом Idle, поделитесь с ним на github, это будет реальной помощью для многих людей, которые изо всех сил пытаются заставить его работать! - person Anton Kizema; 19.01.2015