如何 android 单元测试和模拟静态方法
How to android unit test and mock a static method
嗨,我真的希望你能帮助我,我觉得我这几天一直在拔头发。
我正在尝试为方法 A 编写单元测试。方法 A 调用静态方法 B。我想模拟静态方法 B。
我知道以前有人问过这个问题,但我觉得 Android 从那时起已经成熟了,必须有一种方法可以完成这么简单的任务,而无需重写我要测试的方法。
这里有一个例子,首先是我要测试的方法:
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";
}
}
接下来是我要模拟的静态方法:
public class HelperUtils {
public static int fetchUsernameFromInternet(Context context) {
int userid = 0;
Log.i("HelperUtils ", "hello");
return userid;
}
}
在其他语言中这很容易,但我无法在 Android 中实现。
我试过 Mockito,但似乎不支持静态方法
HelperUtils helper = Mockito.mock(HelperUtils.class);
Mockito.when(helper.fetchUsernameFromInternet(getContext())).thenReturn(1);
这个错误
org.mockito.exceptions.misusing.MissingMethodInvocationException
我试过 Powermock,但我不确定 Android 是否支持它。我设法在我的 gradle 文件中使用 androidCompile 获得了 powermock 运行 但我收到此错误:
Error:Execution failed for task ':app:dexDebugAndroidTest'. com.android.ide.common.process.ProcessException:
更不用说 PowerMockito.mockStatic(HelperUtils.class);
没有 return 任何东西,所以我不知道要将什么传递到我的 getUsername 方法中!
非常感谢任何帮助。
静态方法与任何对象无关 - 你的 helper.fetchUsernameFromInternet(...)
与 HelperUtils.fetchUsernameFromInternet(...)
相同(但有点令人困惑) - 由于这个 [=12],你甚至应该收到编译器警告=].
此外,您必须使用 @RunWith(...)
、@PrepareForTest(...)
和 PowerMockito.mockStatic(...)
来代替 Mockito.mock
来模拟静态方法 - 完整示例在这里:PowerMockito mock single static method and return object
换句话说 - 模拟静态方法(以及构造函数)有点棘手。更好的解决方案是:
如果您可以更改 HelperUtils
,使该方法成为非静态方法,现在您可以使用通常的 Mockito.mock
[ 模拟 HelperUtils
如果您不能更改 HelperUtils
,请创建一个包装器 class 委托给原始 HelperUtils
,但没有 static
方法,然后也使用通常的 Mockito.mock
(这个想法有时称为 "don't mock types you don't own")
我是用 PowerMockito 这样做的。
我正在使用AppUtils.class
,它包含多个静态方法和函数。
静态函数:
public static boolean isValidEmail(CharSequence target) {
return target != null && EMAIL_PATTERN.matcher(target).matches();
}
测试用例:
@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"));
}
}
编辑 1:
添加以下导入:
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertTrue;
希望对您有所帮助。
您可以使用 mockito 最新版本,即 3.4.+,它允许静态模拟
https://javadoc.io/doc/org.mockito/mockito-core/latest/org/mockito/Mockito.html#48
以下是一些解决方案:
- 将你的静态方法修改为non-static方法或者用non-static方法包装你的静态方法,然后直接使用Mockito mock non-static方法中的[=26] =] 测试.
- 如果你不想改变任何原始代码,你可以尝试在Android测试中使用dexmaker-mockito-inline-extended模拟静态方法和final方法。我成功地用它模拟了静态方法。检查这个
solution.
- 在单元测试中使用Robolectric,然后在单元测试中使用PowerMock模拟静态方法。
嗨,我真的希望你能帮助我,我觉得我这几天一直在拔头发。
我正在尝试为方法 A 编写单元测试。方法 A 调用静态方法 B。我想模拟静态方法 B。
我知道以前有人问过这个问题,但我觉得 Android 从那时起已经成熟了,必须有一种方法可以完成这么简单的任务,而无需重写我要测试的方法。
这里有一个例子,首先是我要测试的方法:
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";
}
}
接下来是我要模拟的静态方法:
public class HelperUtils {
public static int fetchUsernameFromInternet(Context context) {
int userid = 0;
Log.i("HelperUtils ", "hello");
return userid;
}
}
在其他语言中这很容易,但我无法在 Android 中实现。 我试过 Mockito,但似乎不支持静态方法
HelperUtils helper = Mockito.mock(HelperUtils.class);
Mockito.when(helper.fetchUsernameFromInternet(getContext())).thenReturn(1);
这个错误
org.mockito.exceptions.misusing.MissingMethodInvocationException
我试过 Powermock,但我不确定 Android 是否支持它。我设法在我的 gradle 文件中使用 androidCompile 获得了 powermock 运行 但我收到此错误:
Error:Execution failed for task ':app:dexDebugAndroidTest'. com.android.ide.common.process.ProcessException:
更不用说 PowerMockito.mockStatic(HelperUtils.class);
没有 return 任何东西,所以我不知道要将什么传递到我的 getUsername 方法中!
非常感谢任何帮助。
静态方法与任何对象无关 - 你的 helper.fetchUsernameFromInternet(...)
与 HelperUtils.fetchUsernameFromInternet(...)
相同(但有点令人困惑) - 由于这个 [=12],你甚至应该收到编译器警告=].
此外,您必须使用 @RunWith(...)
、@PrepareForTest(...)
和 PowerMockito.mockStatic(...)
来代替 Mockito.mock
来模拟静态方法 - 完整示例在这里:PowerMockito mock single static method and return object
换句话说 - 模拟静态方法(以及构造函数)有点棘手。更好的解决方案是:
如果您可以更改
[ 模拟HelperUtils
,使该方法成为非静态方法,现在您可以使用通常的Mockito.mock
HelperUtils
如果您不能更改
HelperUtils
,请创建一个包装器 class 委托给原始HelperUtils
,但没有static
方法,然后也使用通常的Mockito.mock
(这个想法有时称为 "don't mock types you don't own")
我是用 PowerMockito 这样做的。
我正在使用AppUtils.class
,它包含多个静态方法和函数。
静态函数:
public static boolean isValidEmail(CharSequence target) {
return target != null && EMAIL_PATTERN.matcher(target).matches();
}
测试用例:
@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"));
}
}
编辑 1:
添加以下导入:
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertTrue;
希望对您有所帮助。
您可以使用 mockito 最新版本,即 3.4.+,它允许静态模拟
https://javadoc.io/doc/org.mockito/mockito-core/latest/org/mockito/Mockito.html#48
以下是一些解决方案:
- 将你的静态方法修改为non-static方法或者用non-static方法包装你的静态方法,然后直接使用Mockito mock non-static方法中的[=26] =] 测试.
- 如果你不想改变任何原始代码,你可以尝试在Android测试中使用dexmaker-mockito-inline-extended模拟静态方法和final方法。我成功地用它模拟了静态方法。检查这个 solution.
- 在单元测试中使用Robolectric,然后在单元测试中使用PowerMock模拟静态方法。