web-dev-qa-db-ja.com

JSONObject関連の単体テストが失敗するのはなぜですか?

_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);
_

ただし、上記の2つの要求は失敗します。スタックトレースは、channelAssertionとmessageAssertionがnullであると言っていますが、理由はわかりません。私の質問は:上記の2つのアサートが失敗するのはなぜですか?

以下は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$1.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$1.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)
_

EST 5:55 PM 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;
}
_

何らかの理由で、「キーがありませんか????」印刷中ですか?!?!?!?!なぜ?!

EST 6:20 PM EST

単体テストをデバッグする方法を見つけました。デバッガーによると、割り当てられたJSONObjectは_"null"_を返しています。私はこれが何を意味するのか見当がつかない(以下を参照)。これは関連があると思うので、私のgradleファイルには次のものが含まれています。

_testOptions {
    unitTests.returnDefaultValues = true
}
_

テスト内でJSONObjectを作成すると、すべてが正常に機能するため、特に奇妙です。しかし、元のアプリケーションのコードの一部である場合、機能せず、上記のようになります。

enter image description here

35
tambykojak

クラスJSONObjectはAndroid SDKの一部です。つまり、デフォルトでは単体テストに使用できません。

http://tools.Android.com/tech-docs/unit-testing-support から

単体テストの実行に使用されるAndroid.jarファイルには、実際のコードが含まれていません-実際のデバイスのAndroidシステムイメージ。代わりに、すべてのメソッドが例外をスローします(デフォルト)これは、ユニットテストがコードのみをテストし、Androidプラットフォーム(Mockitoを使用して明示的にモックされていないことなど)の特定の動作に依存しないことを確認するためです。

テストオプションを設定するとき

_testOptions {
    unitTests.returnDefaultValues = true
}
_

「方法...モックされていません」を修正しています。問題ですが、結果は、コードがnew JSONObject()を使用する場合、実際のメソッドを使用せず、何もしないモックメソッドを使用し、デフォルト値を返すだけです。それがオブジェクトがnullである理由です。

この質問で問題を解決するさまざまな方法を見つけることができます: Mockitoを使用する場合、Androidメソッドはモックされません

45
Lucas L.

Lucasが言うように、JSONはAndroid SDKにバンドルされているため、スタブで作業しています。

現在の解決策は、次のようにMaven CentralからJSONをプルすることです。

dependencies {
    ...
    testCompile 'org.json:json:20180130'
}

または、jarをダウンロードして含めることができます。

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

不明 Mavenアーティファクトのどのバージョンが、Androidに同梱されているものと正確に/最も密接に対応しています。

これが機能するためには、Android Studio 1.1以上、少なくともビルドツールバージョン22.0.0以上を使用する必要があることに注意してください。

関連問題: #179461

51
David Miguel

さて、私の最初の予想は、getMessage()メソッドがnullを返すことです。あなたの質問でそのメソッドの本体を表示して答えを見つけることができますが、おそらくブレークポイントを使用してAndroidアプリケーションをデバッグする方法を研究する必要があります。
これにより、コードをステップごとに実行し、各ステップで各変数の値を確認できます。それはあっという間にあなたの問題を示し、それはあなたがプログラミングに真剣に関与するつもりなら、できるだけ早く間違いなく習得すべきスキルです。

0
Zoltán