14

Ich versuche, einen Testfall zu schreiben, um eine Klasse zu überprüfen, die in gemeinsame Einstellungen schreibt. Ich benutze Android Studio v1.5.Android Studio: Ich kann nicht in gemeinsame Einstellungen in instrumentiertem Test schreiben

In der guten alten Eklipse wurde bei Verwendung von AndroidTestCase eine zweite APK-Datei auf dem Gerät bereitgestellt, und Tests konnten mit dem Instrumentierungskontext ausgeführt werden, sodass Sie Tests unter Verwendung der gemeinsamen Einstellungen der Instrumentierungs-APK ausführen konnten, ohne die Haupt-APKs zu ändern vorhandene gemeinsame Voreinstellungsdateien.

Ich habe den ganzen Morgen damit verbracht herauszufinden, wie man in Android Studio-Tests einen Nicht-Null-Kontext bekommt. Anscheinend sind Komponententests für Eclipse nicht mit dem Test-Framework von Android Studio kompatibel, da der Aufruf getContext() null zurückgibt. Ich dachte, ich die Antwort in dieser Frage gefunden habe: Get context of test project in Android junit test case

Dinge im Laufe der Zeit verändert haben als alte Versionen von Android Studio nicht die volle Unterstützung beim Test hatte. Viele Antworten sind also nur Hacks. Offenbar jetzt statt InstrumentationTestCase oder AndroidTestCase erstrecken sollten Sie Ihre Tests wie folgt schreiben:

@RunWith(AndroidJUnit4.class) 
public class MyTest { 

    @Test 
    public void testFoo(){ 
     Context instrumentationContext = InstrumentationRegistry.getContext(); 
     Context mainProjectContext = InstrumentationRegistry.getTargetContext();    
    } 
} 

So jetzt habe ich eine nicht null Instrumentierung Kontext haben, und die getSharedPreferences Methode gibt eine Instanz, die aber eigentlich keine Einstellungsdatei zu funktionieren scheint wird geschrieben.

Wenn ich tun:

context = InstrumentationRegistry.getContext();  

Dann wird der SharedPreferences Editor schreibt und schreibt korrekt und keine Ausnahme ausgelöst. Ich kann bei näherer Betrachtung sehen, dass der Editor in diese Datei zu schreiben versucht:

data/data/<package>.test/shared_prefs/PREFS_FILE_NAME.xml 

Aber die Datei wird nie erzeugt noch geschrieben.

jedoch dies mit:

context = InstrumentationRegistry.getTargetContext(); 

der Editor korrekt funktioniert und die Präferenzen in diese Datei geschrieben werden:

/data/data/<package>/shared_prefs/PREFS_FILE_NAME.xml 

Die Einstellungen werden in privaten Modus instanziiert:

SharedPreferences sharedPreferences = context.getSharedPreferences(fileName, Context.MODE_PRIVATE); 

Soweit ich weiß, wurde nach dem Test keine Test-APK auf das Gerät hochgeladen. Dies könnte erklären, warum die Datei nicht mit dem Instrumentierungskontext geschrieben wurde. Ist es möglich, dass dieser Kontext ein gefälschter Kontext ist, der stillschweigend versagt?

Und wenn das der Fall wäre, wie könnte ich einen REAL Instrumentierungskontext erhalten, so dass ich Präferenzen schreiben kann, ohne die Hauptprojekteinstellungen zu ändern?

+0

Sind Ihre Tests im 'test'-Verzeichnis oder unter' testAndroid'? –

+0

Beachten Sie, dass Sie Ihre alten Tests, die 'InstrumentationTestCase' oder' AndroidTestCase' in Android Studio erweitern, weiterhin ausführen können. –

+0

@ Code-Apprentice Dieser Test befindet sich im Ordner androidTest. Ja, Sie können immer noch 'InstrumentationTestCase' und' AndroidTestCase' verwenden, aber Google hat beides sabotiert und 'getContext' gibt null zurück. –

Antwort

3

Es stellt sich heraus, dass Sie nicht über den Instrumentierungskontext in freigegebene Einstellungen schreiben können, und dies galt sogar in Eclipse. Dies wäre der äquivalente Test für die Eklipse:

Ich habe es gerade ausgeführt und es schlägt auch fehl. Die Einstellungen werden nie geschrieben. Ich denke, der Zugriff auf interne Speicherdateien ist in diesem Kontext verboten, da der Aufruf Context.getFilesDir() eine InvocationTargetException auslöst, und auch File.exists() über die Einstellungsdatei aufruft (Sie können überprüfen, mit welcher Datei der Editor den Debugger beschreibt, suchen Sie einfach nach einer privaten Variablen namens mFile innerhalb der this.$0 Mitgliedsinstanz).

Also lag ich falsch, dass dies tatsächlich möglich war. Ich habe zwar den Instrumentierungskontext für Datenzugriffsschichttests in der Vergangenheit verwendet, aber wir haben tatsächlich den Hauptkontext (AndroidTestCase.getContext()) verwendet, obwohl wir für die Präferenzen und SQLite-Dateien unterschiedliche Namen verwendet haben. Aus diesem Grund haben die Komponententests die regulären App-Dateien nicht geändert.

0

Hinweis: Sie können Android Studio weiterhin verwenden, um ältere Tests auszuführen, die InstrumentationTestCase, AndroidTestCase oder ActivityInstrumentationTestCase2 in Android Studio erweitern.

Die neue Testing Support Library bietet ActivityTestRule, um Funktionstests für eine einzelne Aktivität bereitzustellen.Ich glaube, Sie müssen eines dieser Objekte erstellen, bevor Sie versuchen, die für den Test verwendeten Instrumentation und/oder Context zu erhalten. The documentation for Espresso hat ein Beispiel für die Verwendung dieser Klasse.

+0

Schauen Sie mal hier [http://stackoverflow.com/questions/8605611/get-context-of-test-project-in-android-junit-test-case]. Ich sage dir: AndroidTestCase.getContext gibt null zurück. In jedem Fall teste ich keine Aktivitäten und möchte auch keine Testaktivität erstellen, um meinen Test durchzuführen.Wenn möglich würde ich 'AndroidTestCase' mögen, einfach so zu arbeiten, wie es in Eclipse getan hat (ich weiß, wir reden hier über Google, also würde das vielleicht zu viel verlangen) –

+0

@MisterSmith Anscheinend habe ich deine Frage missverstanden. Können Sie etwas Code für die Klasse, die Sie testen, veröffentlichen? –

+0

Ich habe jetzt nicht den Code zur Hand, aber der Test ist sehr einfach: Sie schreiben in gemeinsame Einstellungen und lesen dann, um zu überprüfen, ob die geschriebenen Daten da sind. –

0

Wenn Sie Klassen testen möchten, ohne eine Aktivität erstellen zu müssen, ist es am einfachsten, Robolectric zu verwenden. Robolectric bietet Ihnen einen Mock-Kontext, der alles tut, was ein Kontext tut. In der Tat ist dieser Kontext der Hauptgrund, warum ich Robolectric für Komponententests verwende.

+0

Ich werde es mir ansehen, wenn ich Zeit habe. –

+0

Nehmen Sie sich Zeit. Robolectric war früher sehr einfach zu bedienen, wurde aber mit neueren Versionen von Android komplizierter. – Christine

2

Die Instrumentierung wird zusammen mit Ihrer Anwendung installiert. Die Anwendung läuft selbst und liest und schreibt somit ihre eigenen SharedPreferences.

Es ist seltsam, dass die SharedPreferences der Instrumentation gelöscht (oder nie erstellt), aber selbst wenn sie erstellt würden, würden Sie es schwer haben, sie in Ihre Anwendung im Test zu übergeben. Wie oben erwähnt, wird nur context.getSharedPreferences(); innerhalb Ihrer App aufrufen, wird immer noch die tatsächlichen apps Einstellungen, nie diejenigen Ihrer Instrumentierung.

Sie müssen eine Möglichkeit finden, die Einstellungen für Ihre zu testende Anwendung bereitzustellen. Eine gute Lösung für dieses Problem wäre es, die Einstellungen zu halten in Ihrem Application wie folgt aus:

public class App extends Application { 
    SharedPreferences mPreferences; 
    public void onCreate() { 
     mPreferences = getSharedPreferences(fileName, Context.MODE_PRIVATE); 
    } 

    // add public getter/setter 
} 

Auf diese Weise können Sie

  1. Solange Sie einen Kontext die Präferenzen aus einer Hand bekommen haben mit ((App) context.getApplicationContext()).getPreferences()
  2. Legen Sie die Einstellungen selbst vor Ihre Tests und starten Sie alle Aktivitäten, um Ihre Testdaten zu injizieren.

In Ihrem Test-Setup dann die alle Einstellungen folgende rufen Sie

@Before 
public void before() { 
    ((App) InstrumentationRegistry.getTargetContext()).setPreferences(testPreferences); 
} 

Achten Sie darauf, injizieren müssen Aktivitäten nach jedem Test richtig zu beenden, so dass jeder Test ihre eigenen Abhängigkeiten erhalten können.

Auch sollten Sie stark darüber nachdenken, nur die SharedPreferences Mockito, andere Frameworks zu verspotten, oder einfach die SharedPreferences Schnittstelle selbst implementieren, da dies die Überprüfung von Interaktionen mit Modellen erheblich vereinfacht.

+0

Ich bin mir ziemlich sicher, dass das Öffnen von gemeinsamen Einstellungen mit 'AndroidTestCase.getContext' dazu führte, dass eine Datei unter den apk-Dateien der Instrumentierung erstellt wurde. Ich habe es für mindestens 4 Eclipse-Projekte getan und Tests bestanden, und es war ein wirklich nettes Feature, da die Haupt-APK-Dateien im Gerät nicht verändert wurden. Gleiche Geschichte mit SQLite-Datenbanken. Mit Android Studio gibt es keine Instrumentierungs-APK-Datei auf dem Gerät, und das lässt mich glauben, dass hier ein anderer Mechanismus am Werk ist. –

+0

Ich muss zugeben, dass ich noch nie Instrumentierungstests mit Eclipse durchgeführt habe. Ich bin jedoch davon überzeugt, dass eine Instrumentierungsdatei auf dem Telefon bereitgestellt wird, wie prüfen Sie, ob sie nicht da ist? Normalerweise wird es mit seinem Paketnamen in der Liste der installierten Anwendungen aufgeführt. –

+0

"Mit Android Studio gibt es keine Instrumentierungs-APK-Datei auf dem Gerät bereitgestellt" Nur um zu verdeutlichen, ist dieses Problem ** nicht ** über Android Studio. Es geht um die Bibliotheken, mit denen Sie Ihre Tests schreiben. Die neuere Testing Support Library scheint verschiedene Verhaltensweisen zu haben. Sie sollten dennoch in der Lage sein, das gleiche Verhalten wie in Eclipse unter Verwendung der nativen Instrumentenbibliotheken zu reproduzieren. –