【问题标题】:Apache DefaultHttpClient invocation results in "java.lang.RuntimeException: Stub!"Apache DefaultHttpClient 调用导致“java.lang.RuntimeException:存根!”
【发布时间】:2020-10-17 03:12:54
【问题描述】:

我正在涉足 Android 开发。我有一个将与 RESTful 资源交互的项目,我正在尝试弄清楚如何通过 HTTP 使用参数进行基本 GET。从我读过的所有内容来看,共识似乎更倾向于 HTTPClient 而不是 HttpURLConnection。

我编写了一个包装类,其中包含一个方法,该方法负责实例化密钥对象以使用 HTTPClient 发出请求:

public String get() {  
    String responseString = null;

    HttpClient client = new DefaultHttpClient();
    HttpGet get = new HttpGet();
    try {
        get.setURI(new URI(this.baseURL()));
    } catch (URISyntaxException e1) {
        e1.printStackTrace();
    }

    HttpResponse response;

    try {
        response = client.execute(get);
        responseString = readResponse(response.getEntity());

        if(response != null) {
            System.out.println(responseString);
        }
    } catch(ClientProtocolException e) {
        e.printStackTrace();
    } catch(IOException e) {
        e.printStackTrace();
    }

    return responseString;

}

HttpClient client = new DefaultHttpClient(); 行抛出以下异常:

java.lang.RuntimeException: Stub!
at org.apache.http.impl.client.AbstractHttpClient.<init>(AbstractHttpClient.java:5)
at org.apache.http.impl.client.DefaultHttpClient.<init>(DefaultHttpClient.java:7)
at org.rcindustries.appmap.RestClient.get(RestClient.java:54)
at org.rcindustries.appmap.test.functional.RestClientTest.shouldReturnSomeJSon(RestClientTest.java:26)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
at java.lang.reflect.Method.invoke(Method.java:597)
at org.junit.runners.model.FrameworkMethod$1.runReflectiveCall(FrameworkMethod.java:44)
at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:15)
at org.junit.runners.model.FrameworkMethod.invokeExplosively(FrameworkMethod.java:41)
at org.junit.internal.runners.statements.InvokeMethod.evaluate(InvokeMethod.java:20)
at org.junit.internal.runners.statements.RunBefores.evaluate(RunBefores.java:28)
at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:76)
at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:50)
at org.junit.runners.ParentRunner$3.run(ParentRunner.java:193)
at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:52)
at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:191)
at org.junit.runners.ParentRunner.access$000(ParentRunner.java:42)
at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:184)
at org.junit.runners.ParentRunner.run(ParentRunner.java:236)
at org.eclipse.jdt.internal.junit4.runner.JUnit4TestReference.run(JUnit4TestReference.java:49)
at org.eclipse.jdt.internal.junit.runner.TestExecution.run(TestExecution.java:38)
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:467)
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:683)
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.run(RemoteTestRunner.java:390)
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.main(RemoteTestRunner.java:197)

我看到的每个 HttpClient 示例都使用类似的结构来执行 GET 和 POST。与 Android SDK 捆绑在一起的 Apache Commons 库与标准库有显着不同吗?

【问题讨论】:

    标签: java android unit-testing httpclient apache-commons


    【解决方案1】:

    对于任何可能感兴趣的人,我遇到了一个类似的问题 - 虽然不是 HttpClient 我收到的是 DateUtils 的存根错误。

    Stephen 似乎完全正确 - 作为 Android 平台一部分的类需要启动并运行模拟器:http://simpleprogrammer.com/2010/07/27/the-best-way-to-unit-test-in-android/

    以上链接的快速总结:

    事实上,所有方法都被存根以抛出异常并显示消息“存根!”当你打电话给他们时。好可爱啊。

    真正的 android.jar 实现存在于模拟器或您真正的 Android 设备上。

    因此,您可以进行单元测试...

    • 在模拟器上 - 获得完整的 Android 平台、“真实”的 android 环境等(但没有常用 Java 单元测试工具的功能 - 例如 JMock)

    • 使用 JVM - 速度更快,可以使用 JMock 等单元测试助手,但是您不能测试任何依赖于 Android 平台的东西。

    【讨论】:

    • 看来android.jar SDK库中的所有方法都是stub方法。
    【解决方案2】:

    我认为这是 Android 告诉您不能在该平台上运行该单元测试的方式。涉及与 Android 平台(例如本例中的网络)交互的单元测试需要在实际的 Android 设备或正常运行的 Android 模拟器上运行。

    (它们不能在常规 Eclipse 的上下文中运行。在早期,您需要用于 Eclipse 的 Android 插件。现在(自 2013 年以来)您应该使用基于 Intellij 构建的 Android Studio。)

    显然,您实际所做的是针对 Android SDK 提供的存根类运行单元测试。这永远行不通。

    【讨论】:

    • 所以有些服务/库只有存根的方法? dev.android.com 上是否有任何描述此内容的内容?我是 Android 生态系统的新手,不知道在哪里可以找到它。
    • 我通过“谷歌搜索”异常消息并从您的堆栈跟踪中得出推论来解决这个问题。我自己不做 Android 开发。
    • 一般来说,在 Java 中公开一个只有存根方法的接口是一种常见的做法吗?我已经有一段时间没有使用它了(回到我的大学时代),而且我对 Java 中的 TDD 完全陌生。
    【解决方案3】:

    在 Android SDK 23 中使用 Proguard 和 com.apache.http.legacy 库时会发生这种情况。

    在我将它添加到我的 Proguard 配置后它起作用了:

    -keep class org.apache.http.** { *; }
    -keep class org.apache.commons.codec.** { *; }
    -keep class org.apache.commons.logging.** { *; }
    -keep class android.net.compatibility.** { *; }
    -keep class android.net.http.** { *; }
    -keep class com.android.internal.http.multipart.** { *; }
    -dontwarn org.apache.http.**
    -dontwarn android.webkit.**
    

    这允许系统 Apache 实现正确覆盖编译到应用程序中的存根。

    【讨论】:

      【解决方案4】:

      在 API 28 之后,HttpClient 等旧版库已被弃用,会引发 Stub! 错误,您现在必须将其包含在您的清单文件中:

        <uses-library
         android:name="org.apache.http.legacy"
         android:required="false" />
      

      https://developers.google.com/maps/documentation/android-sdk/config#specify_requirement_for_apache_http_legacy_library

      【讨论】:

        【解决方案5】:

        这个帖子有点老了,但对于不知道的人来说,Robolectric 解决了这个问题进行测试。

        【讨论】:

          猜你喜欢
          • 2012-04-02
          • 1970-01-01
          • 2017-09-04
          • 1970-01-01
          • 2011-08-15
          • 1970-01-01
          • 2020-08-30
          • 2020-10-13
          • 1970-01-01
          相关资源
          最近更新 更多