How to android unit test and mock a static method

后端 未结 4 368
隐瞒了意图╮
隐瞒了意图╮ 2020-12-15 22:39

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

相关标签:
4条回答
  • 2020-12-15 23:05

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

    0 讨论(0)
  • 2020-12-15 23:12

    You can use mockito latest version i.e 3.4.+ which allows static mocking

    https://javadoc.io/doc/org.mockito/mockito-core/latest/org/mockito/Mockito.html#48

    0 讨论(0)
  • 2020-12-15 23:17

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

    Edit 1:

    Add following imports:

    import static org.junit.Assert.assertEquals;
    import static org.junit.Assert.assertFalse;
    import static org.junit.Assert.assertNotNull;
    import static org.junit.Assert.assertTrue;
    

    Hope this would help you.

    0 讨论(0)
  • 2020-12-15 23:27

    Here are some solutions:

    • Modify your static method as a non-static method or wrap your static method with a non-static method, and then directly use Mockito to mock the non-static method in the Android Test.
    • If you don't want to change any original code, you can try to use a dexmaker-mockito-inline-extended to mock static methods and final methods in the Android Test. I successfully mocked the static methods with it. Check this solution.
    • Use a Robolectric in the Unit test and then use PowerMock to mock the static methods in the Unit Test.
    0 讨论(0)
提交回复
热议问题