0

I want to use Espresso to test web calls. I've made a small test app to see if I can get this to work without using AsyncTask. Upon getting data back, a TextView tells the user whether the call was successful or not. I'm making the web call in a new thread.

In my test, I tried following the AdvancedSynchronizationTest as a pattern to making the test wait until the web request is fulfilled. My implementation, however, doesn't seem to work. My understanding is that the method that I'm overriding is ending before the callback is returned to the main activity. If that's the case, I'm overwriting the wrong class. I've also tried overriding runnable itself (see example below) and even changed the UI update to simply setting a boolean, but with no different outcome. Obviously, Espresso doesn't like my using another thread, but why doesn't it pick up that it should wait until the thread is complete? What would be an alternative without using AsyncTask?

You can see the whole project here: https://github.com/bqmackay/EspressoCustomThreadingResourceExample.

Here is the code in question:

MainActivityTest

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();
            }
        }
        };
    }
}

MainActivity

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");
            }
        });
    }
}
4

1 回答 1

2

您在这里并没有真正提出问题,所以我认为问题是关于为什么此设置无法按预期工作。

有(至少)两个原因:

  1. assertTrue(getActivity().isDidThreadReturn());中的断言testThreadRetrieval()根本不等待 IdlingResources 完成。只有ViewInteraction.check()并且ViewInteraction.perform()知道这些,并且会在尝试应用 or 之前检查ViewAssertionIdlingResources ViewAction

  2. 即使assertTrue()应用了之后注释掉的行,它也不起作用,因为检测线程是独立的,不会等待创建的新线程getReps()启动,所以 IdlingResources 的检查可以并且将会在CountingIdlingResource增加之前发生.

如果出于某种原因,您真的不想使用 AsyncTask,您仍然可以从 Espresso 通过使用其执行程序观察 AsynTask 线程池中获益。因此,无需启动单独的线程,只需将 Runnable 提交到AsyncTask.THREAD_POOL_EXECUTOR.

于 2014-04-27T20:19:25.423 回答