Android Asynctask Testing with Android Test Framework

Android AsyncTask testing with Android Test Framework

I met a similar problem while implementing some unit-test. I had to test some service which worked with Executors, and I needed to have my service callbacks sync-ed with the test methods from my ApplicationTestCase classes. Usually the test method itself finished before the callback would be accessed, so the data sent via the callbacks would not be tested. Tried applying the @UiThreadTest bust still didn't work.

I found the following method, which worked, and I still use it. I simply use CountDownLatch signal objects to implement the wait-notify (you can use synchronized(lock){... lock.notify();}, however this results in ugly code) mechanism.

public void testSomething(){
final CountDownLatch signal = new CountDownLatch(1);
Service.doSomething(new Callback() {

@Override
public void onResponse(){
// test response data
// assertEquals(..
// assertTrue(..
// etc
signal.countDown();// notify the count down latch
}

});
signal.await();// wait for callback
}

Android AsyncTask and Mockito (or PowreMockito)

The way your code is set up makes unit testing hard. I'd suggest rearranging it.

The getConfigurationRemote method currently does 3 separate things:

  • creates the AsyncTask
  • defines what that task does
  • executes the task

My solution:

  • move the anonymous AsyncTask to its own class.
  • move the creation of the task (new AsyncTask(....) to a factory class or, better yet, use a dependency injection framework like Dagger.

This is how i imagine it to look like in the end:

private void getConfigurationRemote(final Context context, String url, final ConfigurationManagerListener listener) {
// create the task
ConfigurationRemoteAsyncTask task = taskFactory.createConfigurationRemoteTask(listener);
// Send a request to get the configuration
task.execute(url);
}

Now you can mock and test much more easily:

  • verify that task.execute is called with the given url when .initConfiguration is called by simply mocking the task returned by the task factory.

  • verify that listener.onConfigurationLoaded is called when task.onPostExecute is called, without mocking the whole network infrastructure. This might look like this:

    @Test
    public void init_Configuration_With_Network_Load_JSON_From_Server_Return_To_Listener() {
    ConfigurationRemoteAsyncTask task = new ConfigurationRemoteAsyncTask(mockedListener);
    HashMap<String, Object> config = getNotEmptyConfig();
    task.onPostExecute(config);
    verify(mockedListener).onConfigurationLoaded(any(ConfigWrapper.class));
    }

Testing Android activity with async tasks

It is hard to write tests for a lot of Android functionality, since you can't instantiate classes like Activity outside of Android.

You might be better off doing a true unit test...test the function whose behavior you care about in isolation. Don't try to test it in the context of async task, activity, etc.

You might need to refactor your code a little bit to be able to do that, but its worth it to have testable code!

Android - Unit testing using Instrumentation Framework

Depends a lot on how you're doing things. You could set the test thread waiting (using wait() or a CountDownLatch) and notify it when the AsyncTask finishes.. to do that simply call a protected method within the Activity after the AsyncTask is finished and override that method within your test case to notify the test thread.



Related Topics



Leave a reply



Submit