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
Upload an Image from Camera or Gallery in Webview
Cannot Catch Toolbar Home Button Click Event
Android Webview Inside Scrollview Scrolls Only Scrollview
Why Are These Permissions Being Refused
How to Get the Number of Unread Gmail Mails (On Android)
Which Android Ide Is Better - Android Studio or Eclipse
How to Set Dropdown Arrow in Spinner
How to Get Multiple Icons to Launch Different Activities in One Application
Convert Bitmap Array to Yuv (Ycbcr Nv21)
How to Repeat a Method Every 10 Minutes After a Button Press and End It on Another Button Press
Getintent() Extras Always Null
List of Files in Assets Folder and Its Subfolders
Determining If an Android Device Is Rooted Programmatically
How to Display a Route Between Two Geocoords in Google Maps
How to Set Shadow to a View in Android