问题
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 mockHelperUtils
with the usualMockito.mock
if you can't change
HelperUtils
, create a wrapper class which delegates to the originalHelperUtils
, but doesn't havestatic
methods, and then also use usualMockito.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"));
}
}
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.
来源:https://stackoverflow.com/questions/32074356/how-to-android-unit-test-and-mock-a-static-method