Reputation: 4434
I'm trying to do some unit testing, and I haven't really settle yet on a runner or test class.
At the end, this is the method I'm verifying it works:
public static void getData(final Context context, final Callback<MyObject> callback) {
Locale locale = context.getResources().getConfiguration().locale;
MyObjectService myService = new MyObjectService(getRequestHeaders(context), locale);
}
So I need a mock context that has resources, configuration, locale and SharedPreferences.
I've tried PowerMockito, AndroidTestCase, AndroidTestRunner, ApplicationTestCase. All I can get is a mock Context with nothing in it, or mock Resources, but I can't figure out how to add them to the mock context (basically remake a Context).
This is currently my last attempt (although I've tried more complex ones, without any success):
import com.myApp.android.app.shop.util.ServiceUtils;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.Mockito;
import org.powermock.modules.junit4.PowerMockRunner;
import android.content.Context;
@RunWith(PowerMockRunner.class)
public class TestLogin
{
@Test
public void test()
{
Context context = Mockito.mock(Context.class);
ServiceUtils.getData(context, dataCallback);
}
}
The exception I get is a NPE from getData() as the passed context does not have resources.
Any suggestions?
Upvotes: 0
Views: 3858
Reputation: 5960
As a second answer (and maybe more useful than the first) I suggest you to split the logics from the platform's dependencies.
In this way you can consider to unit test the logic in a pure-java way.
Take a look on MVP pattern. It should helps a lot!
In this case, for example, you would move this line...
MyObjectService myService = new MyObjectService(getRequestHeaders(context), locale);
... inside a "Service" that is completely a pure-java class allocated by a constructor that require (in this case) a String value called "locale" and a data structure called "headers"
Easy, no? ;)
My 2 cents: everytime that you need Robolectric to test logics (instead of UI) you probably make a mistake
Upvotes: 1
Reputation: 5960
Use the RuntimeEnvironment by Robolectric
Locale locale = RuntimeEnvironment.application.getResources().getConfiguration().locale;
Upvotes: 0
Reputation: 12524
Android is not an easily mockable system. I too have tried using Mockito to mock the framework, but it quickly becomes extremely complex. Things like resources and SharedPreferences are not easy to mock. These problems have been tackled in 3rd-party APIs like Robolectric.
I suggest you use Robolectric for your Android unit tests. Robolectric runs in a standard VM (i.e. no emulator needed). Robolectric simulates the majority of the Android system, thus minimizing (but not eliminating) the need to build mocks. I have found it to be a very useful tool for Android TDD.
Upvotes: 3