How to android unit test and mock a static method

匿名 (未验证) 提交于 2019-12-03 02:56:01

问题:

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.

回答1:

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



回答2:

I did this way using PowerMockito.

I am using AppUtils.class, it contains multiple static methods and functions.

Static function:

public static boolean isValidEmail(CharSequence target) {     return target != null && EMAIL_PATTERN.matcher(target).matches(); } 

Test case:

@RunWith(PowerMockRunner.class) @PrepareForTest({AppUtils.class}) public class AppUtilsTest {      @Before     public void setUp() throws Exception {         MockitoAnnotations.initMocks(this);         PowerMockito.mockStatic(AppUtils.class);          PowerMockito.when(AppUtils.isValidEmail(anyString())).thenCallRealMethod();     }      @Test     public void testValidEmail() {         assertTrue(AppUtils.isValidEmail("name@email.com"));     }      @Test     public void testInvalidEmail1() {         assertFalse(AppUtils.isValidEmail("name@email..com"));     }      @Test     public void testInvalidEmail2() {         assertFalse(AppUtils.isValidEmail("@email.com"));     } } 

Hope this would help you.



标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!