Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to android unit test and mock a static method

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.

like image 271
James Avatar asked Aug 18 '15 13:08

James


People also ask

Can I mock static class in unit test?

You can use Moq to mock non-static methods but it cannot be used to mock static methods. Although static methods cannot be mocked easily, there are a few ways to mock static methods. You can take advantage of the Moles or Fakes framework from Microsoft to mock static method calls.

Can you mock a static method?

Since static method belongs to the class, there is no way in Mockito to mock static methods.

How do you unit test a static method?

There are three ways to test the code that calls static methods: Create a wrapper class and use dependency injection. Use a static Func property. Use the Extract and override call.

How do I mock a method in Android?

To create a mock object for an Android dependency, add the @Mock annotation before the field declaration. To stub the behavior of the dependency, you can specify a condition and return value when the condition is met by using the when() and thenReturn() methods.


1 Answers

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")

like image 127
iirekm Avatar answered Sep 21 '22 18:09

iirekm