2015-09-03 7 views
20

Ich bin mit meinen Tests gradle testFlavorTypeWarum ist mein mit JSONObject zusammenhängender Komponententest fehlgeschlagen?

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 erfolgreich verwendet wird.

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 obigen zwei Anforderungen schlagen fehl. Der Stack-Trace besagt, dass channelAssertion und messageAssertion null sind, aber nicht sicher warum. Meine Frage ist: Warum sind die obigen zwei behauptet fehlgeschlagen?

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 finden Sie die 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) 

EDIT 05.55 EST

ich herausgefunden habe, dass ich durch Laufen mit System.out.println("") und dann die Ergebnisse anmelden können 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 ????" druckt?!?!?!?! Warum?!

EDIT 06.20 EST

Ich habe herausgefunden, wie Unit-Tests zu debuggen. Entsprechend dem Debugger gibt das zugewiesene JSONObject "null" zurück. Ich habe keine Ahnung, was das bedeutet (siehe unten). Da ich denke, das ist relevant, meine gradle Datei beinhaltet folgende Leistungen:

testOptions { 
    unitTests.returnDefaultValues = true 
} 

Es ist besonders merkwürdig, weil, wenn ich einen JSONObject innerhalb des Tests konstruieren, dann fein alles funktioniert. Aber wenn es Teil des Codes der ursprünglichen Anwendung ist, dann funktioniert es nicht und macht das Obige.

enter image description here

+0

Fügen Sie bitte die Stapelüberwachung hinzu. –

+0

@ Zoltán, ich habe die Stack-Trace hinzugefügt. – tambykojak

+0

Das hat früher funktioniert, aber es scheint, dass es jetzt unter Instrumentenartefakt ausgeführt werden muss. – mbmc

Antwort

28

Die Klasse JSONObject ist Teil des android SDK. Dies bedeutet, dass standardmäßig kein Komponententest verfügbar ist.

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

Die android.jar-Datei, die verwendet wird, Unit-Tests laufen nicht enthalten eine tatsächliche Code - das ist durch das Android-System Bild auf realen Geräte zur Verfügung gestellt.Stattdessen werfen alle Methoden Ausnahmen (standardmäßig). Dies ist , um sicherzustellen, dass Ihre Unit-Tests nur Ihren Code testen und nicht auf ein bestimmtes Verhalten der Android-Plattform (die Sie nicht explizit verspottet, z. B. mit Mockito) abhängen.

Wenn Sie die Testoptionen zu

testOptions { 
    unitTests.returnDefaultValues = true 
} 

Sie sind Befestigungs "Method ... nicht spotten." Problem, aber das Ergebnis ist, dass, wenn Ihr Code new JSONObject() verwendet Sie nicht die echte Methode verwenden, verwenden Sie eine Mock-Methode, die nichts tut, es gibt nur einen Standardwert zurück. Das ist der Grund, warum das Objekt null ist.

können Sie verschiedene Möglichkeiten, das Problem finden in dieser Frage zu lösen: Android methods are not mocked when using Mockito

0

Nun, wäre meine erste Vermutung sein, dass Ihre getMessage() Methode null zurückgibt. Sie könnten den Körper dieser Methode in Ihrer Frage zeigen und lassen Sie uns die Antwort für Sie finden, aber Sie sollten wahrscheinlich erforschen, wie man Android-Anwendungen mit Haltepunkten debuggt.
Auf diese Weise können Sie Ihren Code Schritt für Schritt ausführen und die Werte der einzelnen Variablen bei jedem Schritt sehen. Das würde Ihnen in kürzester Zeit Ihr Problem zeigen und es ist eine Fähigkeit, die Sie auf jeden Fall so schnell wie möglich beherrschen sollten, wenn Sie ernsthaft in die Programmierung einsteigen wollen.

+0

Danke für die Antwort und den Vorschlag. Ich habe bereits den Hauptteil der 'getMessage()' Methode zur Verfügung gestellt. Es ist Teil der 'SlackMessageRequest', hast du dir das angeschaut? Ich sehe nicht, wie es aber null sein könnte. Ich bin ziemlich vertraut mit dem Debuggen, aber ich führe diese Tests im Terminal durch, so dass ich keine Möglichkeit gefunden habe, sie zu debuggen. Irgendwelche Vorschläge, wie ich das erreichen kann? – tambykojak

+0

@tambykojak vielleicht kann dies helfen https://www.bignerdranch.com/blog/triumph-android-studio-1-2-sneaks-in-full-testing-support/ meine nächste Ahnung wäre, dass "Nachricht" und 'channel' sind' null', wenn sie an den Konstruktor übergeben werden. Sie haben den Teil des Codes, in dem Sie diese Variablen initialisieren, nicht angezeigt. Wenn das Einrichten einer Debugging-Umgebung zu kompliziert ist, können Sie immer temporäre Protokollierung zwischen einigen Zeilen hinzufügen. –

+0

Ich habe dieses Blog mehrmals gelesen, aber es löst dieses Problem nicht. Selbst wenn 'channel' und' test' 'null' sind, sollte der Test basierend auf der bereitgestellten Logik dennoch bestehen. – tambykojak

19

Wie Lucas sagt, ist JSON mit dem Android SDK gebündelt, so dass Sie mit einem Stummel arbeiten.

Die aktuelle Lösung ist JSON von Maven Zentral wie diese ziehen:

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

Alternativ können Sie herunterladen und schließen Sie das Glas:

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

Es ist not known, welche Version des Maven Artefakt entspricht genau/am ehesten denen, die mit Android ausgeliefert werden.

Beachten Sie, dass Sie auch Android Studio 1.1 oder höher verwenden und mindestens die Tools Version 22.0.0 oder höher erstellen müssen, damit dies funktioniert.

In Verbindung stehendes Problem: #179461

+0

Das funktioniert nicht mehr für mich. Bei einem alten Projekt, aber jetzt bekomme ich immer noch 'null', wenn ich versuche, ein neues 'JSONObject' zu erstellen. Ich benutze 'testCompile 'org.json: json: 20160810''. Ich habe auch 'configurations.all {resolutionStrategy.force 'org.json: json: 20160810'}' versucht, aber kein Glück. Irgendwelche Ideen? – AutonomousApps

+0

Ich habe gerade in meiner gramle Ausgabe gefunden: 'WARNUNG: Abhängigkeit org.json: JSON: 20160810 wird für FlavorDebug ignoriert, da es Konflikte mit der internen Version von Android sein kann. Im Falle eines Problems, packen Sie bitte mit Jarjar um die Klassenpakete zu ändern " – AutonomousApps

+0

Vielen Dank. Sie haben keine Ahnung, wie viel diese Lösung meinem Blutdruck hilft. – jwehrle