繁体   English   中英

如何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,但出现此错误:

错误:任务 ':app:dexDebugAndroidTest' 的执行失败。 com.android.ide.common.process.ProcessException:

更不用说PowerMockito.mockStatic(HelperUtils.class); 不返回任何内容,所以我不知道将什么传递给我的 getUsername 方法!

任何帮助将不胜感激。

静态方法与任何对象无关 - 您的helper.fetchUsernameFromInternet(...)helper.fetchUsernameFromInternet(...)相同(但有点令人困惑HelperUtils.fetchUsernameFromInternet(...) - 由于此helper.fetchUsernameFromInternet程序,您甚至应该收到编译器警告helper.fetchUsernameFromInternet

更重要的是,而不是Mockito.mock来模拟你必须使用的静态方法: @RunWith(...)@PrepareForTest(...)然后PowerMockito.mockStatic(...) - 完整的例子在这里: PowerMockito mock单个静态方法和返回对象

换句话说 - 模拟静态方法(以及构造函数)有点棘手。 更好的解决办法是:

  • 如果你可以改变HelperUtils ,使该方法非静态,现在你可以嘲笑HelperUtils与通常Mockito.mock

  • 如果你不能改变HelperUtils ,创建一个包装类,它委托给原来的HelperUtils ,但没有static方法,然后也使用通常的Mockito.mock (这个想法有时被称为“不要模拟你不喜欢的类型” t拥有")

我使用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

以下是一些解决方案:

  • 将你的静态方法修改为非静态方法或者将你的静态方法包装成一个非静态方法,然后在Android Test中直接使用Mockito模拟非静态方法。
  • 如果不想改动任何原始代码,可以尝试使用dexmaker-mockito-inline-extended来模拟 Android Test 中的静态方法和最终方法。 我成功地用它模拟了静态方法。 检查此解决方案
  • 在单元测试中使用Robolectric ,然后使用 PowerMock 模拟单元测试中的静态方法。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM