TooManyEduardos
TooManyEduardos

Reputation: 4434

How to get Locale from mock context

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

Answers (3)

Tommaso Resti
Tommaso Resti

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

Tommaso Resti
Tommaso Resti

Reputation: 5960

Use the RuntimeEnvironment by Robolectric

Locale locale = RuntimeEnvironment.application.getResources().getConfiguration().locale;

Upvotes: 0

EJK
EJK

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

Related Questions