Warum schlägt mein JSONObject-bezogener Komponententest fehl?

Lesezeit: 8 Minuten

Benutzer-Avatar
tambykojak

Ich führe meine Tests mit aus 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"));

Der obige Test ist erfolgreich.

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

Aber die beiden oben genannten Anfragen schlagen fehl. Der Stack-Trace sagt, dass channelAssertion und messageAssertion null sind, aber nicht sicher warum. Meine Frage ist: Warum schlagen die beiden obigen Behauptungen fehl?

Unten ist die 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
}

Unten ist der Stacktrace:

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)

BEARBEITEN 17:55 EST

Ich habe herausgefunden, dass ich mich mit anmelden kann System.out.println("") und sehen Sie sich dann die Ergebnisse an, indem Sie laufen gradle testFlavorType --debug und durch Versuch und Irrtum habe ich die folgende seltsame Situation entdeckt:

@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;
}

Aus irgendeinem Grund “Es gibt keine Schlüssel????” wird ausgedruckt?!?!?!?! Warum?!

BEARBEITEN 18:20 Uhr EST

Ich habe herausgefunden, wie man Unit-Tests debuggt. Laut Debugger gibt das zugewiesene JSONObject zurück "null". Ich habe keine Ahnung, was das bedeutet (siehe unten). Da ich dies für relevant halte, enthält meine Gradle-Datei Folgendes:

testOptions {
    unitTests.returnDefaultValues = true
}

Es ist besonders seltsam, denn wenn ich ein JSONObject innerhalb des Tests konstruiere, funktioniert alles einwandfrei. Wenn es jedoch Teil des Codes der ursprünglichen Anwendung ist, funktioniert es nicht und führt das oben Gesagte aus.

Geben Sie hier die Bildbeschreibung ein

  • Bitte fügen Sie den Stack-Trace hinzu.

    – Zoltán

    3. September 2015 um 21:06 Uhr

  • @Zoltán, ich habe den Stack-Trace hinzugefügt.

    – Tambykojak

    3. September 2015 um 21:11 Uhr

  • Früher hat das funktioniert, aber es scheint, dass es jetzt unter Instrumentierungsartefakt ausgeführt werden muss.

    – mbc

    11. November 2015 um 20:47 Uhr

Benutzer-Avatar
David Miguel

Wie Lucas sagt, ist JSON mit dem Android SDK gebündelt, sodass Sie mit einem Stub arbeiten.

Die aktuelle Lösung besteht darin, JSON wie folgt aus Maven Central zu ziehen:

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

Sie können die Version ersetzen 20210307 mit dem das neuste abhängig von der Android-API. Es ist nicht bekannt, welche Version des Maven-Artefakts genau/am ehesten dem entspricht, was mit Android geliefert wird.

Alternativ können Sie das JAR herunterladen und einfügen:

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

Beachten Sie, dass Sie auch Android Studio 1.1 oder höher verwenden und mindestens Version 22.0.0 oder höher der Build-Tools benötigen, damit dies funktioniert.

Verwandtes Problem: #179461

  • Das funktioniert bei mir nicht mehr. Es tat auf einem alten Projekt, aber jetzt bekomme ich immer noch null wenn Sie versuchen, eine neue zu erstellen JSONObject. Ich benutze testCompile 'org.json:json:20160810'. Ich habe es auch versucht configurations.all { resolutionStrategy.force 'org.json:json:20160810' }, aber kein Glück. Irgendwelche Ideen?

    – AutonomeApps

    18. Januar 2017 um 1:33 Uhr

  • Ich habe gerade das in meiner Gradle-Ausgabe gefunden: WARNING: Dependency org.json:json:20160810 is ignored for flavorDebug as it may be conflicting with the internal version provided by Android. In case of problem, please repackage with jarjar to change the class packages

    – AutonomeApps

    18. Januar 2017 um 1:51 Uhr


  • Vielen Dank. Sie haben keine Ahnung, wie sehr diese Lösung meinem Blutdruck hilft.

    – jwehrle

    14. März 2017 um 22:31 Uhr

  • Die Version ist sehr alt und funktioniert möglicherweise nicht. Verwenden org.json:json:20180130.

    – Maskerade

    29. März 2018 um 11:38 Uhr

  • Da testCompile veraltet ist, können Sie verwenden testImplementation 'org.json:json:20201115' Vergessen Sie nicht zu reinigen, bevor Sie Ihre Tests erneut ausführen

    – Luft eins

    18. Februar 2021 um 9:25 Uhr


Benutzer-Avatar
Lukas L.

Die Klasse JSONObject ist Teil des Android SDK. Das bedeutet, dass es standardmäßig nicht für Komponententests verfügbar ist.

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

Die android.jar-Datei, die zum Ausführen von Unit-Tests verwendet wird, enthält keinen eigentlichen Code – der vom Android-System-Image auf echten Geräten bereitgestellt wird. Stattdessen lösen alle Methoden (standardmäßig) Ausnahmen aus. Dies soll sicherstellen, dass Ihre Komponententests nur Ihren Code testen und nicht von einem bestimmten Verhalten der Android-Plattform abhängen (das Sie nicht explizit verspottet haben, z. B. mit Mockito).

Wenn Sie die Testoptionen auf einstellen

testOptions {
    unitTests.returnDefaultValues = true
}

Sie fixieren die “Methode … nicht verspottet”. Problem, aber das Ergebnis ist, dass, wenn Ihr Code verwendet new JSONObject() Sie verwenden nicht die echte Methode, Sie verwenden eine Scheinmethode, die nichts tut, sondern nur einen Standardwert zurückgibt. Das ist der Grund, warum das Objekt ist null.

In dieser Frage finden Sie verschiedene Lösungsansätze: Android-Methoden werden bei der Verwendung von Mockito nicht gemockt

Nun, meine erste Vermutung wäre, dass Ihre getMessage() Methode zurück null. Sie könnten den Hauptteil dieser Methode in Ihrer Frage zeigen und uns die Antwort für Sie finden lassen, aber Sie sollten wahrscheinlich recherchieren, wie Sie Android-Anwendungen mithilfe von Haltepunkten debuggen können.
Auf diese Weise können Sie Ihren Code Schritt für Schritt ausführen und die Werte jeder Variable bei jedem Schritt sehen. Das würde Ihnen Ihr Problem in kürzester Zeit zeigen, und es ist eine Fähigkeit, die Sie auf jeden Fall so schnell wie möglich beherrschen sollten, wenn Sie beabsichtigen, sich ernsthaft mit dem Programmieren zu beschäftigen.

  • Danke für die Antwort und den Vorschlag. Ich habe bereits den Körper der bereitgestellt getMessage() Methode. Es ist Teil der SlackMessageRequest, hast du dir das angeschaut? Ich sehe jedoch nicht, wie es null sein könnte. Ich bin mit dem Debuggen ziemlich vertraut, aber ich führe diese Tests im Terminal aus, sodass ich keine Möglichkeit gefunden habe, sie zu debuggen. Irgendwelche Vorschläge, wie ich das erreichen kann?

    – Tambykojak

    3. September 2015 um 21:26 Uhr


  • @tambykojak vielleicht kann das helfen bignerdranch.com/blog/… das wäre meine nächste vermutung message und channel sind null wenn es an den Konstruktor übergeben wird. Sie haben den Teil des Codes nicht gezeigt, in dem Sie diese Variablen initialisieren. Wenn das Einrichten einer Debugging-Umgebung zu kompliziert ist, können Sie immer noch eine temporäre Protokollierung zwischen einigen Zeilen hinzufügen.

    – Zoltán

    3. September 2015 um 21:33 Uhr

  • Ich habe diesen Blog mehrmals gelesen, aber er löst das Problem nicht. Selbst wenn channel und test sind nullsollte der Test basierend auf der bereitgestellten Logik trotzdem bestanden werden.

    – Tambykojak

    3. September 2015 um 21:43 Uhr

  • Ja, damit sollte es funktionieren null, sie haben Recht. Wie auch immer. Fügen Sie etwas Protokollierung oder einfach hinzu System.out.println an wichtigen Teilen und sehen, wo die nulls kommen aus.

    – Zoltán

    3. September 2015 um 21:49 Uhr

1158130cookie-checkWarum schlägt mein JSONObject-bezogener Komponententest fehl?

This website is using cookies to improve the user-friendliness. You agree by using the website further.

Privacy policy