Beispiel für die Ausrichtung auf eine App

Diese Kategorie von Instrumentierungstests unterscheidet sich nicht wesentlich von Tests für reguläre Android-Anwendungen. Die Testanwendung, die die Instrumentierung enthält, muss mit demselben Zertifikat signiert werden wie die Anwendung, auf die sie ausgerichtet ist.

In diesem Leitfaden wird davon ausgegangen, dass Sie bereits über einige Kenntnisse des Workflow des Plattform-Quellbaums verfügen. Wenn nicht, lesen Sie bitte die Anforderungen. In diesem Beispiel wird ein neuer Instrumentierungstest mit dem Zielpaket erstellt, das auf das eigene Testanwendungspaket festgelegt ist. Wenn Sie mit dem Konzept nicht vertraut sind, lesen Sie die Einführung in das Plattformtesten.

In diesem Leitfaden wird der folgende Test als Beispiel verwendet:

  • frameworks/base/packages/Shell/tests

Es wird empfohlen, sich zuerst einen groben Überblick über den Code zu verschaffen, bevor Sie fortfahren.

Quellspeicherort auswählen

Da der Instrumentierungstest auf eine Anwendung ausgerichtet ist, wird der Testquellcode üblicherweise in einem tests-Verzeichnis im Stammverzeichnis des Komponentenquellverzeichnisses im Plattformquellbaum platziert.

Weitere Informationen zum Quellspeicherort finden Sie im End-to-End-Beispiel für selbstinstrumentierende Tests.

Manifestdatei

Wie bei einer regulären Anwendung benötigt jedes Instrumentierungstestmodul eine Manifestdatei. Wenn Sie die Datei als AndroidManifest.xml benennen und sie neben Android.mk für Ihr Testmodul bereitstellen, wird sie automatisch in das BUILD_PACKAGE-Core-Makefile aufgenommen.

Bevor Sie fortfahren, empfehlen wir Ihnen dringend, zuerst die Übersicht über App-Manifeste zu lesen.

Hier finden Sie eine Übersicht über die grundlegenden Komponenten einer Manifestdatei und ihre Funktionen.

Die aktuelle Version der Manifestdatei für die Beispiel-Gerrit-Änderung ist unter folgender Adresse verfügbar: https://android.googlesource.com/platform/frameworks/base/+/android16-release/packages/Shell/tests/AndroidManifest.xml

Hier ist ein Snapshot zur Veranschaulichung:

<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 Anmerkungen zur Manifestdatei:

<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="com.android.shell.tests">

Das Attribut package ist der Name des Anwendungspakets. Dies ist die eindeutige Kennung, die das Android-Anwendungsframework zur Identifizierung einer Anwendung (oder in diesem Kontext: Ihrer Testanwendung) verwendet. Jeder Nutzer 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 ist, das Suffix .test hinzuzufügen.

Außerdem entspricht dieses package-Attribut dem, was ComponentName#getPackageName() zurückgibt, und dem, was Sie für die Interaktion mit verschiedenen pm-Unterbefehlen über adb shell verwenden würden.

Beachten Sie außerdem, dass der Paketname zwar in der Regel dem Stil eines Java-Paketnamens entspricht, aber tatsächlich nur sehr wenig damit zu tun hat. Das bedeutet, dass Ihr Anwendungs- oder Testpaket Klassen mit beliebigen Paketnamen enthalten kann. Sie können aber auch den Namen des 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 enthalten sind. Daher sind zusätzliche Classpath-Einträge erforderlich, wenn das Testpaket vom Anwendungs-Framework aufgerufen wird.

android:targetPackage="com.android.shell"

Dadurch wird das Zielpaket der Instrumentierung auf com.android.shell festgelegt. Wenn die Instrumentierung über den Befehl am instrument aufgerufen wird, startet das Framework den Prozess com.android.shell neu und fügt Instrumentierungscode in den Prozess für die Testausführung ein. Das bedeutet auch, dass der Testcode Zugriff auf alle Klasseninstanzen hat, die in der zu testenden Anwendung ausgeführt werden. Je nach den bereitgestellten Testhooks kann er möglicherweise den Status ändern.

Einfache Konfigurationsdatei

Jedes neue Testmodul muss eine Konfigurationsdatei haben, um das Build-System mit Modulmetadaten, Compile-Time-Abhängigkeiten und Verpackungsanweisungen zu versorgen. 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 auch eine Testkonfigurationsdatei für die Testumgebung von Android, Trade Federation, schreiben.

In der Testkonfiguration können spezielle Optionen für die Geräteeinrichtung und Standardargumente für die Testklasse angegeben werden.

Die aktuelle Version der Konfigurationsdatei für die Beispiel-Gerrit-Änderung ist unter frameworks/base/packages/Shell/tests/AndroidTest.xml verfügbar.

Hier ist ein Snapshot zur Veranschaulichung:

<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 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 mithilfe eines angegebenen target_preparer auf dem Zielgerät zu installieren. Entwicklern stehen in Trade Federation viele Zielvorbereiter zur Verfügung, mit denen sie dafür sorgen können, dass das Gerät vor der Ausführung des Tests richtig 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>

Damit wird die Trade Federation-Testklasse angegeben, die zum Ausführen des Tests verwendet werden soll. Außerdem wird das Paket auf dem Gerät übergeben, das ausgeführt werden soll, sowie das Test-Runner-Framework, in diesem Fall JUnit.

Weitere Informationen zu Testmodulkonfigurationen

JUnit4-Funktionen

Wenn Sie die android-support-test-Bibliothek als Test-Runner verwenden, können Sie neue Testklassen im JUnit4-Stil übernehmen. Die Beispiel-Gerrit-Änderung enthält einige sehr einfache Anwendungsbeispiele für die Funktionen.

Der aktuelle Quellcode für die Beispiel-Gerrit-Änderung ist unter frameworks/base/packages/Shell/tests/src/com/android/shell/BugreportReceiverTest.java verfügbar.

Testmuster sind in der Regel spezifisch für Komponententeams. Es gibt jedoch einige allgemein nützliche Nutzungsmuster.

@SmallTest
@RunWith(AndroidJUnit4.class)
public final class FeatureFactoryImplTest {

Ein wesentlicher Unterschied zu JUnit4 besteht darin, dass Tests nicht mehr von einer gemeinsamen Basistestklasse abgeleitet werden müssen. Stattdessen schreiben Sie Tests in einfachen Java-Klassen und verwenden Annotationen, um bestimmte Testkonfigurationen und Einschränkungen anzugeben. In diesem Beispiel wird angegeben, dass diese Klasse als Android-JUnit4-Test ausgeführt werden soll.

Mit der Annotation @SmallTest wurde eine Testgröße für die gesamte Testklasse angegeben. Alle Testmethoden, die dieser Testklasse hinzugefügt werden, übernehmen diese Annotation für die Testgröße. Vorbereitung der Testklasse, Bereinigung nach dem Test und Bereinigung nach der Testklasse: Ähnlich wie die Methoden setUp und tearDown in JUnit4. Die Test-Annotation wird verwendet, um den eigentlichen Test zu annotieren.

    @Before
    public void setup() {
    ...
    @Test
    public void testGetProvider_shouldCacheProvider() {
    ...

Die Annotation @Before 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 die Bereinigung nach dem Test. Die Annotationen @BeforeClass und @AfterClass können von JUnit4 für Methoden verwendet werden, um vor der Ausführung aller Tests in einer Testklasse die Einrichtung und danach die Bereinigung durchzuführen. Die Einrichtungs- und Abbruchmethoden für den Klassenbereich müssen statisch sein.

Im Gegensatz zu früheren Versionen von JUnit müssen Testmethoden nicht mehr mit test beginnen. Stattdessen muss jede von ihnen mit @Test annotiert werden. Wie gewohnt müssen Testmethoden öffentlich sein, dürfen keinen Rückgabewert deklarieren, keine Parameter annehmen und können Ausnahmen auslösen.

        Context context = InstrumentationRegistry.getTargetContext();

Da für JUnit4-Tests keine gemeinsame Basisklasse mehr erforderlich ist, ist es nicht mehr notwendig, Context-Instanzen über getContext() oder getTargetContext() über Basisklassenmethoden abzurufen. Stattdessen werden sie vom neuen Test-Runner über InstrumentationRegistry verwaltet, in dem die vom Instrumentierungsframework erstellte kontextbezogene und umgebungsbezogene Einrichtung gespeichert wird. In dieser Klasse können Sie auch Folgendes aufrufen:

  • getInstrumentation(): die Instanz der Klasse Instrumentation
  • getArguments(): Die Befehlszeilenargumente, die über -e <key> <value> an am instrument übergeben werden.

Lokal erstellen und testen

Verwenden Sie für die häufigsten Anwendungsfälle Atest.

Bei komplexeren Fällen, die eine stärkere Anpassung erfordern, folgen Sie der Anleitung zur Instrumentierung.