如何对JSON解析进行单元测试?

内容来源于 Stack Overflow,并遵循CC BY-SA 3.0许可协议进行翻译与使用

  • 回答 (2)
  • 关注 (0)
  • 查看 (277)

我正在从Android Web应用程序中下载JSON数据。解析数据的类看起来像这样:

public class JsonCourseParser implements CourseParser {

    public Course parseCourse(String courseData) {
        Course result;

        try {
            JSONObject jsonObject = new JSONObject(courseData);

            ...

            result = new Course("foo", "bar");
        } catch (JSONException e) {
            result = null;
        }

        return result;
    }
}

这样构建得很好,它parseCourse()在我的应用程序中调用时起作用,但是当我尝试在单元测试中测试此方法时,我得到以下异常:

java.lang.NoClassDefFoundError: org/json/JSONException
    at JsonCourseParserTest.initClass(JsonCourseParserTest.java:15)
    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.RunBefores.evaluate(RunBefores.java:27)
    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)
Caused by: java.lang.ClassNotFoundException: org.json.JSONException
    at java.net.URLClassLoader$1.run(URLClassLoader.java:202)
    at java.security.AccessController.doPrivileged(Native Method)
    at java.net.URLClassLoader.findClass(URLClassLoader.java:190)
    at java.lang.ClassLoader.loadClass(ClassLoader.java:307)
    at sun.misc.Launcher$AppClassLoader.loadClass(Launcher.java:301)
    at java.lang.ClassLoader.loadClass(ClassLoader.java:248)
    ... 16 more

看起来,org.jsonAndroid Framework附带的软件包的类在默认情况下不可用于Java。

有没有一种方法可以解决这个问题,以便我可以单元测试解析JSON的类?

提问于
用户回答回答于

只需将以下行添加到build.gradle中的依赖项部分即可:

testCompile 'org.json:json:20140107'

请注意,还需要使用Android Studio 1.1或更高版本,并且至少需要构建工具版本22.0.0或更高版本才能使用!

testCompile意味着依赖项被包含在内,因为测试依赖项只有在您的项目正在编译执行单元测试时才会使用。提供的jar不会包含在APK中,只会用于替换org.json包中缺少的类。

用户回答回答于

我找到了这个答案。它不能解决我的问题,但至少可以解释为什么会有问题。

首先,我做了一个错误的假设,即JSONObjectorg.json包中导入(作为JRE的一部分)。它不是 - 在一个Android项目中,它驻留在android.jar(经典的“duh”时刻)。

这一发现提升了我的自信心。这很容易通过android.jar在我的单元测试项目中添加一个引用来解决,或者至少是我想了一会儿。这样做只会在运行我的测试时给我另一个错误:

java.lang.RuntimeException: Stub!
    at org.json.JSONObject.<init>(JSONObject.java:8)
    ...

至少这给了我更多的谷歌。然而,我发现,并不是真的令人鼓舞(又一个经典的“唔”时刻)......

这个博客很好地描述了这个问题:为什么Android还没有准备好用于TDD,以及我如何尝试。如果你不打算阅读整个事情,简单的解释如下:

这里的问题是随SDK提供的android.jar被删除而没有实现代码。似乎预计的解决方案是,您应该在模拟器或真正的手机上运行单元测试。

在进一步做这些事情时,我发现了几篇文章,博客,以及关于这个问题的SO问题。最后,我会在这里添加一些链接,以供那些可能需要查看的链接:

如果你环顾四周,还有更多。

在许多链接中,有很多建议/解决方案/ Android的单元测试的替代方法,但我不打算尝试根据该方法做出正确答案(因为显然有太多方法我还不知道关于Android开发)。如果有人有任何不错的提示,我会很高兴听到他们:)

经过多次试验后,我实际上找到了解决这个特定问题的工作解决方案。我之所以没有尝试这个,是因为我认为我曾经在某个地方读过,在我的Android应用中包含“普通”java库会有问题。我尝试了很多不同的方法来解决我的问题,所以我想我也会试试这个方法 - 它确实有效!这里是:

  • org.json从这里下载了“真实” 软件包的源代码:http : //www.json.org/java/index.html
  • 接下来,我编译了源代码并将它们一起打包在我自己的json.jar中
  • 我将新创建的json.jar添加到我的项目的构建路径(我的Android应用程序的主项目,而不是测试项目)

没有改变我的代码,没有改变我的测试,只添加这个库。一切正常,我的Android应用程序和我的单元测试。

我还在调试模式下测试了代码,在调试Android应用程序时JSONObject,我JsonCourseParser从Android SDK(android.jar)中获取,但是在调试我的单元测试时,它从我自己的json.jar中获取。不确定这是否意味着我的应用程序构建时不包含json.jar,或者如果运行时智能地选择了正确的库来使用。也不知道这个额外的库可能对我的最终应用程序有任何其他影响。我想只有时间会告诉...

扫码关注云+社区