Diese Kategorie von Instrumentierungstests unterscheidet sich nicht wesentlich von denen, die auf normale Android-Anwendungen abzielen. Es ist zu beachten, dass die Testanwendung, die die Instrumentierung enthielt, mit demselben Zertifikat signiert sein muss wie die Anwendung, auf die sie abzielt.
Beachten Sie, dass in dieser Anleitung davon ausgegangen wird, dass Sie bereits über einige Kenntnisse im Quellbaum-Workflow der Plattform verfügen. Wenn nicht, lesen Sie bitte die Anforderungen . Das hier behandelte Beispiel ist das Schreiben eines neuen Instrumentierungstests, bei dem das Zielpaket auf ein eigenes Testanwendungspaket eingestellt ist. Wenn Sie mit dem Konzept nicht vertraut sind, lesen Sie bitte die Einführung zum Plattformtest durch.
In diesem Leitfaden wird der folgende Test als Beispiel verwendet:
- Frameworks/Base/Pakete/Shell/Tests
Es empfiehlt sich, zunächst den Code durchzublättern, um sich einen groben Eindruck zu verschaffen, bevor Sie fortfahren.
Entscheidung über einen Quellort
Da der Instrumentierungstest auf eine Anwendung abzielt, besteht die Konvention darin, den Testquellcode in einem tests
unter dem Stammverzeichnis Ihres Komponentenquellverzeichnisses im Plattformquellbaum zu platzieren.
Weitere Diskussionen zum Quellenstandort finden Sie im End-to-End-Beispiel für selbstinstrumentierende Tests .
Manifestdatei
Genau wie eine normale Anwendung benötigt jedes Instrumentierungstestmodul eine Manifestdatei. Wenn Sie die Datei AndroidManifest.xml
nennen und sie neben Android.mk
für Ihr Test-Tmodul bereitstellen, wird sie automatisch vom BUILD_PACKAGE
Kern-Makefile eingebunden.
Bevor Sie fortfahren, wird dringend empfohlen, zunächst die App-Manifest-Übersicht durchzugehen.
Dies gibt einen Überblick über die grundlegenden Komponenten einer Manifestdatei und ihre Funktionalitäten.
Die neueste Version der Manifestdatei für die Beispiel-Gerrit-Änderung kann unter https://android.googlesource.com/platform/frameworks/base/+/main/packages/Shell/tests/AndroidManifest.xml abgerufen werden
Der Einfachheit halber ist hier ein Schnappschuss enthalten:
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.android.shell.tests">
<application>
<uses-library android:name="android.test.runner" />
<activity
android:name="com.android.shell.ActionSendMultipleConsumerActivity"
android:label="ActionSendMultipleConsumer"
android:theme="@android:style/Theme.NoDisplay"
android:noHistory="true"
android:excludeFromRecents="true">
<intent-filter>
<action android:name="android.intent.action.SEND_MULTIPLE" />
<category android:name="android.intent.category.DEFAULT" />
<data android:mimeType="*/*" />
</intent-filter>
</activity>
</application>
<instrumentation android:name="android.support.test.runner.AndroidJUnitRunner"
android:targetPackage="com.android.shell"
android:label="Tests for Shell" />
</manifest>
Einige ausgewählte Anmerkungen zur Manifestdatei:
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.android.shell.tests">
Das package
ist der Name des Anwendungspakets: Dies ist die eindeutige Kennung, die das Android-Anwendungsframework verwendet, um eine Anwendung (oder in diesem Zusammenhang: Ihre Testanwendung) zu identifizieren. Jeder Benutzer im System kann nur eine Anwendung mit diesem Paketnamen installieren.
Da es sich um ein Testanwendungspaket handelt, das unabhängig vom zu testenden Anwendungspaket ist, muss ein anderer Paketname verwendet werden: Eine gängige Konvention besteht darin, ein Suffix .test
hinzuzufügen.
Darüber hinaus ist dieses package
dasselbe wie das, was ComponentName#getPackageName()
zurückgibt, und auch dasselbe, das Sie für die Interaktion mit verschiedenen pm
Unterbefehlen über adb shell
verwenden würden.
Bitte beachten Sie auch, dass der Paketname zwar normalerweise den gleichen Stil hat wie ein Java-Paketname, aber eigentlich nur sehr wenig damit zu tun hat. Mit anderen Worten: Ihr Anwendungs- (oder Test-)Paket kann Klassen mit beliebigen Paketnamen enthalten. Sie können sich jedoch auch für Einfachheit entscheiden und den Namen Ihres Java-Pakets der obersten Ebene in Ihrer Anwendung oder Ihrem Test mit dem Namen des Anwendungspakets identisch machen.
<uses-library android:name="android.test.runner" />
Dies ist für alle Instrumentierungstests erforderlich, da die zugehörigen Klassen in einer separaten Framework-JAR-Bibliotheksdatei gepackt sind und daher zusätzliche Klassenpfadeinträge erforderlich sind, wenn das Testpaket vom Anwendungsframework aufgerufen wird.
android:targetPackage="com.android.shell"
Dadurch wird das Zielpaket der Instrumentierung auf com.android.shell
gesetzt. Wenn die Instrumentierung über den Befehl am instrument
aufgerufen wird, startet das Framework den Prozess com.android.shell
neu und fügt Instrumentierungscode zur Testausführung in den Prozess ein. Dies bedeutet auch, dass der Testcode Zugriff auf alle Klasseninstanzen hat, die in der getesteten Anwendung ausgeführt werden, und möglicherweise den Zustand manipulieren kann, abhängig von den bereitgestellten Test-Hooks.
Einfache Konfigurationsdatei
Jedes neue Testmodul muss über eine Konfigurationsdatei verfügen, um das Build-System mit Modulmetadaten, Abhängigkeiten zur Kompilierungszeit und Verpackungsanweisungen zu steuern. In den meisten Fällen ist die Soong-basierte Blueprint-Dateioption ausreichend. Weitere Informationen finden Sie unter Einfache Testkonfiguration .
Komplexe Konfigurationsdatei
Für komplexere Tests müssen Sie außerdem eine Testkonfigurationsdatei für Androids Testumgebung Trade Federation schreiben.
Die Testkonfiguration kann spezielle Geräte-Setup-Optionen und Standardargumente zur Bereitstellung der Testklasse angeben.
Die neueste Version der Konfigurationsdatei für die Beispiel-Gerrit-Änderung kann unter Frameworks/base/packages/Shell/tests/AndroidTest.xml abgerufen werden
Der Einfachheit halber ist hier ein Schnappschuss enthalten:
<configuration description="Runs Tests for Shell.">
<target_preparer class="com.android.tradefed.targetprep.TestAppInstallSetup">
<option name="test-file-name" value="ShellTests.apk" />
</target_preparer>
<option name="test-suite-tag" value="apct" />
<option name="test-tag" value="ShellTests" />
<test class="com.android.tradefed.testtype.AndroidJUnitTest" >
<option name="package" value="com.android.shell.tests" />
<option name="runner" value="android.support.test.runner.AndroidJUnitRunner" />
</test>
</configuration>
Einige ausgewählte Anmerkungen zur Testkonfigurationsdatei:
<target_preparer class="com.android.tradefed.targetprep.TestAppInstallSetup">
<option name="test-file-name" value="ShellTests.apk"/>
</target_preparer>
Dadurch wird Trade Federation angewiesen, ShellTests.apk mit einem angegebenen target_preparer auf dem Zielgerät zu installieren. Den Entwicklern in Trade Federation stehen viele Zielvorbereiter zur Verfügung, mit denen sichergestellt werden kann, dass das Gerät vor der Testausführung ordnungsgemäß eingerichtet ist.
<test class="com.android.tradefed.testtype.AndroidJUnitTest">
<option name="package" value="com.android.shell.tests"/>
<option name="runner" value="android.support.test.runner.AndroidJUnitRunner"/>
</test>
Dies gibt die Trade Federation-Testklasse an, die zum Ausführen des Tests verwendet werden soll, und übergibt das Paket auf dem auszuführenden Gerät sowie das Test-Runner-Framework, in diesem Fall JUnit.
Weitere Informationen zu Testmodulkonfigurationen finden Sie hier
JUnit4-Funktionen
Die Verwendung android-support-test
Bibliothek als Testläufer ermöglicht die Übernahme neuer Testklassen im JUnit4-Stil, und die Beispiel-Gerrit-Änderung enthält einige sehr grundlegende Verwendungen ihrer Funktionen.
Der aktuelle Quellcode für die Beispiel-Gerrit-Änderung kann unter folgender Adresse abgerufen werden: Frameworks/Base/Packages/Shell/tests/src/com/android/shell/BugreportReceiverTest.java
Während Testmuster in der Regel spezifisch für Komponententeams sind, gibt es einige allgemein nützliche Nutzungsmuster.
@SmallTest
@RunWith(AndroidJUnit4.class)
public final class FeatureFactoryImplTest {
Ein wesentlicher Unterschied in JUnit4 besteht darin, dass Tests nicht mehr von einer gemeinsamen Basistestklasse erben müssen; Stattdessen schreiben Sie Tests in einfachen Java-Klassen und verwenden Annotationen, um bestimmte Testeinstellungen und Einschränkungen anzugeben. In diesem Beispiel weisen wir an, dass diese Klasse als Android JUnit4-Test ausgeführt werden soll.
Die Annotation @SmallTest
gab eine Testgröße für die gesamte Testklasse an: Alle zu dieser Testklasse hinzugefügten Testmethoden erben diese Annotation zur Testgröße. Klassenaufbau vor dem Test, Abbau nach dem Test und Abbau der Klasse nach dem Test: ähnlich den Methoden setUp
und tearDown
in JUnit4. Test
werden zum Kommentieren des eigentlichen Tests verwendet.
@Before
public void setup() {
...
@Test
public void testGetProvider_shouldCacheProvider() {
...
Die @Before
Annotation wird von JUnit4 für Methoden verwendet, um die Einrichtung vor dem Test durchzuführen. Obwohl in diesem Beispiel nicht verwendet, gibt es auch @After
für den Teardown nach dem Test. In ähnlicher Weise können die Annotationen @BeforeClass
und @AfterClass
für Methoden von JUnit4 verwendet werden, um vor der Ausführung aller Tests in einer Testklasse ein Setup durchzuführen und anschließend ein Teardown durchzuführen. Beachten Sie, dass die Setup- und Teardown-Methoden für den Klassenbereich statisch sein müssen.
Was die Testmethoden betrifft, so müssen sie im Gegensatz zu früheren Versionen von JUnit den Methodennamen nicht mehr mit test
beginnen, sondern jede von ihnen muss mit @Test
annotiert werden. Wie üblich müssen Testmethoden öffentlich sein, keinen Rückgabewert deklarieren, keine Parameter annehmen und dürfen Ausnahmen auslösen.
Context context = InstrumentationRegistry.getTargetContext();
Da die JUnit4-Tests keine gemeinsame Basisklasse mehr erfordern, ist es nicht mehr erforderlich, Context
Instanzen über getContext()
oder getTargetContext()
über Basisklassenmethoden abzurufen; Stattdessen verwaltet der neue Testläufer sie über InstrumentationRegistry
, wo vom Instrumentierungsframework erstellte Kontext- und Umgebungseinstellungen gespeichert werden. Über diese Klasse können Sie auch Folgendes aufrufen:
-
getInstrumentation()
: die Instanz derInstrumentation
Klasse -
getArguments()
: die Befehlszeilenargumente, die über-e <key> <value>
anam instrument
übergeben werden
Lokal erstellen und testen
Für die häufigsten Anwendungsfälle verwenden Sie Atest .
Befolgen Sie bei komplexeren Fällen, die eine umfassendere Anpassung erfordern, die Anweisungen zur Instrumentierung .