Mocking Android Async Tasks with Mockito and running it in Robolectric

2,549 views
Skip to first unread message

Vineeth B S

unread,
Feb 18, 2014, 12:14:50 AM2/18/14
to robol...@googlegroups.com
I am spying on an object of class DownloadTask(which is an android async task). In the spied object, I am calling methods downloadTask.execute(url); These methods help me execute the "doInBackground()" and "onPostExecute()" of the downloadTask object. Inside the doInBackground(), I am creating a "HttpURLConnection" object, to which I pass a url(kinda like a factory method), On the returned object, In the test, I am "verifying" if "getInputStream" is getting called on it. I see from the test that I have written that I am "verifying" if the method is called on a different object(hence the failure). Can you please suggest me a way to mock the method, so that I can "verify" on the appropriate object. I have attached Code snippets below:


DownloadTaskTest.Java
=============================================================
@Test
public void execute_shouldOpenInputStreamOfConnection() throws IOException{
    HttpURLConnection connectionMock = setMockConnection();
    downloadTask.execute("http://www.google.com");   
    Mockito.verify(connectionMock).getInputStream();
}
private HttpURLConnection setMockConnection() throws IOException {
    HttpURLConnection connectionMock = Mockito.mock(HttpURLConnection.class);
    Mockito.doReturn(connectionMock).when(downloadTask).createConnection(Mockito.any(URL.class));
    return connectionMock;
}
---------------------------------------------------------------------------------------------------------------------------

DownloadTask.Java
==============================================================
public class DownloadTask extends AsyncTask<String, Integer, String> {
protected String doInBackground(String... params) {
    URL url = null;
    InputStream input = null;
    OutputStream output = null;
    HttpURLConnection connection = null;
    try {
        url = new URL(params[0]);
        connection = this.createConnection(url);
        input = connection.getInputStream();
    } catch (MalformedURLException e) {
        e.printStackTrace();
    } catch (IOException e1) {
        e1.printStackTrace();
    }
    public HttpURLConnection createConnection(URL url) throws IOException {
    HttpURLConnection connection;
    connection = (HttpURLConnection) url.openConnection();
    return connection;
}
}
}

Thanks
Vineeth BS

Mike Grafton

unread,
Feb 19, 2014, 10:21:35 AM2/19/14
to robol...@googlegroups.com
Vineeth,

Robolectric has built in support for AsyncTask. Any call to execute() on an AsyncTask will not execute the doInBackground() method immediately; rather the task gets put onto a list of tasks to run, which you can then execute with Robolectric. runBackgroundTasks(). So if I understand your code correctly, your task isn't executing. Try it in the debugger to be sure.

That being said, the usage of HttpUrlConnection will cause you trouble. I'd try to use Android's implementation of HttpClient where possible, since Robolectric intercepts all calls to that library and lets you set up canned responses to your HTTP calls. We're looking at doing the same for HttpUrlConnection, though it's not clear when that'll happen.

Mike


--
You received this message because you are subscribed to the Google Groups "Robolectric" group.
To unsubscribe from this group and stop receiving emails from it, send an email to robolectric...@googlegroups.com.
For more options, visit https://groups.google.com/groups/opt_out.

Vineeth B S

unread,
Feb 19, 2014, 11:52:04 AM2/19/14
to robol...@googlegroups.com
Dear Mike,

Thanks for taking time to look into this.
I did use the Robolectric.runBackgroundTasks();
[missed including that part of the code :(  ] to start the execution.

Do you have any suggestions that we could benefit from while TDDing Android code.

Coming back to my question, is it appropriate to use Mockito to mock the calls along with Robolectric. Is the behavior described by me(instead of mockito returning stubs, calls to actual method happens) expected? I observed this behavior when I used Mockito + Robolectric + AsyncTasks. It worked fine when I used the same with Services instead of AsyncTasks.

Thanks
Vineeth BS

--
Regards
Vineeth B S

Mike Grafton

unread,
Feb 21, 2014, 8:52:12 PM2/21/14
to robol...@googlegroups.com
I think it's appropriate to use Mockito in this case, though in my opinion it is a testing style that you want to use minimally. Mocking out dependencies that have fine-grained APIs causes a lot of headaches and doesn't feel very satisfying. Maybe you write one test that way, and but wrapping that code in an object with a cleaner/narrower interface that is easier to mock will result in better testing results. Your DownloadTask itself might be that object.

Mike

Vineeth B S

unread,
Feb 25, 2014, 8:48:25 AM2/25/14
to robol...@googlegroups.com
Dear Mike,

Thanks for the suggestion. We are going to try this out.

Thanks
Vineeth BS
Reply all
Reply to author
Forward
0 new messages