为什么我的 JSONObject 相关单元测试失败了?

Why is my JSONObject related unit test failing?

我 运行 我的测试使用 gradle testFlavorType

JSONObject jsonObject1 = new JSONObject();
JSONObject jsonObject2 = new JSONObject();
jsonObject1.put("test", "test");
jsonObject2.put("test", "test");
assertEquals(jsonObject1.get("test"), jsonObject2.get("test"));

以上测试成功

jsonObject = new SlackMessageRequest(channel, message).buildBody();
String channelAssertion = jsonObject.getString(SlackMessageRequest.JSON_KEY_CHANNEL);
String messageAssertion = jsonObject.getString(SlackMessageRequest.JSON_KEY_TEXT);
assertEquals(channel, channelAssertion);
assertEquals(message, messageAssertion);

但是上面两个请求都失败了。堆栈跟踪表明 channelAssertion 和 messageAssertion 为空,但不确定原因。我的问题是:为什么以上两个断言都失败了?

下面是SlackMessageRequest.

public class SlackMessageRequest
        extends BaseRequest {
    // region Variables

    public static final String JSON_KEY_TEXT = "text";
    public static final String JSON_KEY_CHANNEL = "channel";

    private String mChannel;
    private String mMessage;

    // endregion

    // region Constructors

    public SlackMessageRequest(String channel, String message) {
        mChannel = channel;
        mMessage = message;
    }

    // endregion

    // region Methods

    @Override
    public MethodType getMethodType() {
        return MethodType.POST;
    }    

    @Override
    public JSONObject buildBody() throws JSONException {
        JSONObject body = new JSONObject();
        body.put(JSON_KEY_TEXT, getMessage());
        body.put(JSON_KEY_CHANNEL, getChannel());
        return body;
    }

    @Override
    public String getUrl() {
        return "http://localhost:1337";
    }

    public String getMessage() {
        return mMessage;
    }

    public String getChannel() {
        return mChannel;
    }

// endregion
}

下面是堆栈跟踪:

junit.framework.ComparisonFailure: expected:<@tk> but was:<null>
    at junit.framework.Assert.assertEquals(Assert.java:100)
    at junit.framework.Assert.assertEquals(Assert.java:107)
    at junit.framework.TestCase.assertEquals(TestCase.java:269)
    at com.example.app.http.request.SlackMessageRequestTest.testBuildBody(SlackMessageRequestTest.java:30)
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at java.lang.reflect.Method.invoke(Method.java:483)
    at junit.framework.TestCase.runTest(TestCase.java:176)
    at junit.framework.TestCase.runBare(TestCase.java:141)
    at junit.framework.TestResult.protect(TestResult.java:122)
    at junit.framework.TestResult.runProtected(TestResult.java:142)
    at junit.framework.TestResult.run(TestResult.java:125)
    at junit.framework.TestCase.run(TestCase.java:129)
    at junit.framework.TestSuite.runTest(TestSuite.java:252)
    at junit.framework.TestSuite.run(TestSuite.java:247)
    at org.junit.internal.runners.JUnit38ClassRunner.run(JUnit38ClassRunner.java:86)
    at org.gradle.api.internal.tasks.testing.junit.JUnitTestClassExecuter.runTestClass(JUnitTestClassExecuter.java:86)
    at org.gradle.api.internal.tasks.testing.junit.JUnitTestClassExecuter.execute(JUnitTestClassExecuter.java:49)
    at org.gradle.api.internal.tasks.testing.junit.JUnitTestClassProcessor.processTestClass(JUnitTestClassProcessor.java:64)
    at org.gradle.api.internal.tasks.testing.SuiteTestClassProcessor.processTestClass(SuiteTestClassProcessor.java:50)
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at java.lang.reflect.Method.invoke(Method.java:483)
    at org.gradle.messaging.dispatch.ReflectionDispatch.dispatch(ReflectionDispatch.java:35)
    at org.gradle.messaging.dispatch.ReflectionDispatch.dispatch(ReflectionDispatch.java:24)
    at org.gradle.messaging.dispatch.ContextClassLoaderDispatch.dispatch(ContextClassLoaderDispatch.java:32)
    at org.gradle.messaging.dispatch.ProxyDispatchAdapter$DispatchingInvocationHandler.invoke(ProxyDispatchAdapter.java:93)
    at com.sun.proxy.$Proxy2.processTestClass(Unknown Source)
    at org.gradle.api.internal.tasks.testing.worker.TestWorker.processTestClass(TestWorker.java:106)
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at java.lang.reflect.Method.invoke(Method.java:483)
    at org.gradle.messaging.dispatch.ReflectionDispatch.dispatch(ReflectionDispatch.java:35)
    at org.gradle.messaging.dispatch.ReflectionDispatch.dispatch(ReflectionDispatch.java:24)
    at org.gradle.messaging.remote.internal.hub.MessageHub$Handler.run(MessageHub.java:360)
    at org.gradle.internal.concurrent.DefaultExecutorFactory$StoppableExecutorImpl.run(DefaultExecutorFactory.java:64)
    at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1142)
    at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617)
    at java.lang.Thread.run(Thread.java:745)

编辑5:55PM EST

我发现我可以使用 System.out.println("") 登录,然后通过 运行 gradle testFlavorType --debug 查看结果,通过反复试验,我发现了以下奇怪的情况:

@Override
public JSONObject buildBody() throws JSONException {
    System.out.println("buildBody mChannel = " + mChannel);
    System.out.println("buildBody mMessage = " + mMessage);
    JSONObject body = new JSONObject();
    body.put(JSON_KEY_TEXT, getMessage());
    body.put(JSON_KEY_CHANNEL, getChannel());

    if (body.length() != 0) {
        Iterator<String> keys = body.keys();

        if (keys.hasNext()) {
            do {
                String key = keys.next();
                System.out.println("keys: " + key);
            } while (keys.hasNext());
        }
    } else {
        System.out.println("There are no keys????");
    }

    return body;
}

出于某种原因,"There are no keys????" 正在打印出来?!?!?!?!为什么?!

编辑6:20PM EST

我已经知道如何调试单元测试了。根据调试器,分配的 JSONObject 正在返回 "null"。我不知道这意味着什么(见下文)。因为我认为这是相关的,所以我的 gradle 文件包括以下内容:

testOptions {
    unitTests.returnDefaultValues = true
}

这特别奇怪,因为如果我在测试中构造一个 JSONObject,那么一切都会正常。但如果它是原始应用程序代码的一部分,则它不起作用并执行上述操作。

嗯,我的第一个预感是您的 getMessage() 方法 returns null。您可以在您的问题中展示该方法的主体,让我们为您找到答案,但您可能应该研究如何使用断点调试 android 应用程序。
这样您就可以 运行 一步一步地编写代码,并在每一步查看每个变量的值。这会立即向您展示您的问题,如果您打算认真参与编程,那么您绝对应该尽快掌握这项技能。

class JSONObject 是 android SDK 的一部分。这意味着默认情况下不可用于单元测试。

来自http://tools.android.com/tech-docs/unit-testing-support

The android.jar file that is used to run unit tests does not contain any actual code - that is provided by the Android system image on real devices. Instead, all methods throw exceptions (by default). This is to make sure your unit tests only test your code and do not depend on any particular behaviour of the Android platform (that you have not explicitly mocked e.g. using Mockito).

当您将测试选项设置为

testOptions {
    unitTests.returnDefaultValues = true
}

您正在修复 "Method ... not mocked." 问题,但结果是,当您的代码使用 new JSONObject() 时,您没有使用真正的方法,而是使用了一个不执行任何操作的模拟方法,它只是 returns 一个默认值。这就是对象 null.

的原因

您可以找到解决此问题的不同方法:

正如 Lucas 所说,JSON 与 Android SDK 捆绑在一起,因此您使用的是存根。

当前的解决方案是像这样从 Maven Central 拉取 JSON:

dependencies {
    ...
    testImplementation 'org.json:json:20210307'
}

您可以将版本 20210307 替换为 the latest one depending on the Android API. It is ,maven 工件的版本对应 exactly/most 与 Android.

附带的版本非常接近

或者,您可以下载并包含 jar:

dependencies {
    ...
    testImplementation files('libs/json.jar')
}

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

相关问题:#179461