Reputation: 175
I'm testing an Android app using an ApplicationTestCase. I want to mock one of my AsyncTasks (example simplified to show the problem):
public class Foo extends AsyncTask<Void,Void,Void> {
@Override
protected Void doInBackground(Void... unused) {
return null;
}
}
So to set up my tests, I did the following:
private Foo mockFoo;
@Override
protected void setUp() throws Exception {
super.setUp()
mockFoo = mock(Foo.class);
createApplication();
}
And then the actual test is the following:
public void testAsyncTaskMock() {
mockFoo.execute();
verify(mockFoo).execute();
}
But I get an exception when mockFoo.execute();
runs:
java.lang.NullPointerException: Attempt to invoke virtual method 'int android.os.AsyncTask$Status.ordinal()' on a null object reference
Why is that technique of mocking the AsyncTask not working?
Note that removing createApplication();
causes the problem to go away in this simple case, but for my actual testing I do need the application to be created.
Upvotes: 2
Views: 3738
Reputation: 95654
AsyncTask.execute is final, and Mockito can't mock final classes or methods.
- Cannot mock final methods - their real behavior is executed without any exception. Mockito cannot warn you about mocking final methods so be vigilant.
Specifically, this is because Java can resolve the link at compile time, which means Mockito can't use its generated subclasses and method overrides to change the behavior.
You may choose to use Powermock, which uses a special classloader to rewrite the old behavior, or Robolectric, which does the same but replaces classes with Android-specific test-friendly alternate implementations ("shadows") including one for AsyncTask.
Upvotes: 7