How to android unit test and mock a static method

James picture James · Aug 18, 2015 · Viewed 18.1k times · Source

Hi I really hope you can help me, I feel like I've been pulling my hair out for days.

I'm trying to write unit tests for a method A. Method A calls a static method B. I want to mock static method B.

I know this has been asked before, but I feel Android has matured since then, and there must be a way to do such a simple task without re-writing the methods I want to test.

Here is an example, first the method I want to test:

public String getUserName(Context context, HelperUtils helper) {
    if(helper == null){
        helper = new HelperUtils();
    }
    int currentUserId = helper.fetchUsernameFromInternet(context);

    if (currentUserId == 1) {
        return "Bob";
    } else {
        return "Unknown";
    }
}

Next the static method I want to mock:

public class HelperUtils {
    public static int fetchUsernameFromInternet(Context context) {
        int userid = 0;

        Log.i("HelperUtils ", "hello");

        return userid;
    }
}

In other languages this is so easy but I just can't make it work in Android. I've tried Mockito, but it appears static methods aren't supported

HelperUtils helper = Mockito.mock(HelperUtils.class);
Mockito.when(helper.fetchUsernameFromInternet(getContext())).thenReturn(1);

This errors

org.mockito.exceptions.misusing.MissingMethodInvocationException

I've tried Powermock but I'm not completely sure this is supported by Android. I managed to get powermock running using androidCompile in my gradle file but I get this error:

Error:Execution failed for task ':app:dexDebugAndroidTest'. com.android.ide.common.process.ProcessException:

Not to mention PowerMockito.mockStatic(HelperUtils.class); Doesn't return anything, so I don't know what to pass into my getUsername method!

Any help would be so very much appreciated.

Answer

iirekm picture iirekm · Nov 12, 2015

Static methods aren't related to any object - your helper.fetchUsernameFromInternet(...) is the same (but a bit confusing) as HelperUtils.fetchUsernameFromInternet(...) - you should even get a compiler warning due to this helper.fetchUsernameFromInternet.

What's more, instead of Mockito.mock to mock static methods you have to use: @RunWith(...), @PrepareForTest(...) and then PowerMockito.mockStatic(...) - complete example is here: PowerMockito mock single static method and return object

In other words - mocking static methods (and also constructors) is a bit tricky. Better solution is:

  • if you can change HelperUtils, make that method non-static and now you can mock HelperUtils with the usual Mockito.mock

  • if you can't change HelperUtils, create a wrapper class which delegates to the original HelperUtils, but doesn't have static methods, and then also use usual Mockito.mock (this idea is sometimes called "don't mock types you don't own")