Ausrichtung auf ein App-Beispiel

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

In diesem Leitfaden wird davon ausgegangen, dass Sie bereits über Kenntnisse des Quellstruktur-Workflows der Plattform verfügen. Falls nicht, lesen Sie den Abschnitt Anforderungen. Das hier behandelte Beispiel ist das Schreiben eines neuen Instrumentierungstests mit einem Zielpaket, das auf ein eigenes Testanwendungspaket festgelegt ist. Wenn Sie mit dem Konzept nicht vertraut sind, lesen Sie den Hilfeartikel Einführung in Plattformtests.

In diesem Leitfaden wird der folgende Test als Beispiel verwendet:

  • Frameworks/Basis/Pakete/Shell/Tests

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

Quellspeicherort auswählen

Da der Instrumentierungstest auf eine Anwendung ausgerichtet ist, wird der Test-Quellcode gemäß der Konvention im Stammverzeichnis des Komponentenquellenverzeichnisses im Plattform-Quellbaum in einem tests-Verzeichnis abgelegt.

Weitere Informationen zum Speicherort der Quelle finden Sie im End-to-End-Beispiel für selbstinstrumentierte 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 Testmodul angeben, wird sie automatisch in das BUILD_PACKAGE-Kern-Makefile aufgenommen.

Bevor Sie fortfahren, sollten Sie sich die Übersicht zum App-Manifest ansehen.

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

Die aktuelle Version der Manifestdatei für die Beispiel-Gerrit-Änderung finden Sie unter: https://android.googlesource.com/platform/frameworks/base/+/main/packages/Shell/tests/AndroidManifest.xml

Hier ist ein Snapshot für Sie:

<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 Attribut package ist der Name des Anwendungspakets. Dies ist die eindeutige Kennung, mit der das Android-Anwendungsframework eine Anwendung (oder in diesem Kontext: Ihre Testanwendung) identifiziert. 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 besteht darin, ein Suffix .test hinzuzufügen.

Darüber hinaus entspricht dieses package-Attribut dem, was ComponentName#getPackageName() zurückgibt, und dasselbe, das Sie verwenden würden, um mit verschiedenen pm-Unterbefehlen über adb shell zu interagieren.

Beachten Sie auch, dass der Paketname zwar in der Regel den gleichen Stil wie der Name eines Java-Pakets hat, aber eigentlich nur wenig damit zu tun hat. Mit anderen Worten, Ihr Anwendungs- oder Testpaket kann Klassen mit beliebigen Paketnamen enthalten. Sie können sich aber auch für die Einfachheit entscheiden und den Namen des Java-Pakets der obersten Ebene in Ihrer Anwendung oder Ihrem Test verwenden, der mit dem Namen des Anwendungspakets identisch ist.

<uses-library android:name="android.test.runner" />

Dies ist für alle Instrumentierungstests erforderlich, da die zugehörigen Klassen in einer separaten JAR-Bibliotheksdatei des Frameworks verpackt sind. Daher sind zusätzliche Klassenpfad-Einträge erforderlich, wenn das Testpaket vom Anwendungsframework 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 com.android.shell-Prozess neu und fügt dem Prozess für die Testausführung Instrumentierungscode hinzu. Dies bedeutet auch, dass der Testcode Zugriff auf alle Klasseninstanzen hat, die in der zu testenden Anwendung ausgeführt werden, und den Status möglicherweise abhängig von den bereitgestellten Test-Hooks ändern kann.

Einfache Konfigurationsdatei

Jedes neue Testmodul muss eine Konfigurationsdatei haben, um das Buildsystem mit Modulmetadaten, Abhängigkeiten zur Kompilierungszeit und Verpackungsanweisungen zu steuern. In den meisten Fällen reicht die Option für die Blueprint-Datei auf Songbasis aus. Weitere Informationen finden Sie unter Einfache Testkonfiguration.

Komplexe Konfigurationsdatei

Bei komplexeren Tests müssen Sie auch eine Testkonfigurationsdatei für die Trade Federation von Android schreiben.

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

Die neueste Version der Konfigurationsdatei für die Beispiel-Gerrit-Änderung finden Sie unter: frameworks/base/packages/Shell/tests/AndroidTest.xml

Hier ist ein Snapshot für Sie:

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

Damit wird die Trade Federation angewiesen, die Datei "ShellTests.apk" mit einem angegebenen "target_preparer" auf dem Zielgerät zu installieren. In Trade Federation stehen Entwicklern viele Zielvorbereitungstools zur Verfügung, mit denen sie dafür sorgen können, dass das Gerät vor der Testausführung 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>

Hier wird die Trade Federation-Testklasse für die Ausführung des Tests angegeben. Außerdem werden das Paket auf dem Gerät, das ausgeführt werden soll, und das Test-Runner-Framework übergeben, in diesem Fall JUnit.

Weitere Informationen zu Testmodulkonfigurationen

Funktionen von JUnit4

Die Verwendung der android-support-test-Bibliothek als Test-Runner ermöglicht die Übernahme neuer JUnit4-Testklassen. Die Gerrit-Änderung im Beispiel enthält einige sehr einfache Verwendungen der Funktionen.

Den aktuellen Quellcode für die Beispieländerung in Gerrit finden Sie unter: frameworks/base/packages/Shell/tests/src/com/android/shell/BugreportReceiverTest.java

Testmuster sind in der Regel spezifisch für Komponententeams, aber es gibt einige allgemein nützliche Nutzungsmuster.

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

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

Mit der @SmallTest-Anmerkung wurde eine Testgröße für die gesamte Testklasse angegeben: Alle Testmethoden, die dieser Testklasse hinzugefügt werden, übernehmen diese Anmerkung zur Testgröße. Vorbereitung der Testklasse, Aufräumen nach dem Test und Aufräumen nach dem Test der Klasse: ähnelt den Methoden setUp und tearDown in JUnit4. Die Test-Anmerkung wird für den eigentlichen Test verwendet.

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

Die @Before-Anmerkung wird von JUnit4 auf Methoden angewendet, um die Vorabeinrichtung für den Test durchzuführen. In diesem Beispiel wird @After nicht verwendet, aber es gibt auch eine Option für den Abbau nach dem Test. Ebenso können die Anmerkungen @BeforeClass und @AfterClass von JUnit4 auf Methoden angewendet werden, um vor der Ausführung aller Tests in einer Testklasse die Einrichtung und danach die Deaktivierung durchzuführen. Die Einrichtungs- und Teardown-Methoden für den Klassenbereich müssen statisch sein.

Anders als in früheren Versionen von JUnit muss der Methodenname bei den Testmethoden nicht mehr mit test beginnen. Stattdessen muss jede Methode mit @Test annotiert werden. Wie üblich müssen Testmethoden öffentlich sein, keinen Rückgabewert deklarieren, keine Parameter verwenden und Ausnahmen auslösen.

        Context context = InstrumentationRegistry.getTargetContext();

Da für JUnit4-Tests keine gemeinsame Basisklasse mehr erforderlich ist, müssen Context-Instanzen nicht mehr über getContext() oder getTargetContext() über Basisklassenmethoden abgerufen werden. Stattdessen werden sie vom neuen Test-Runner über InstrumentationRegistry verwaltet, wo die vom Instrumentierungs-Framework erstellte Kontext- und Umgebungseinrichtung gespeichert wird. Über diesen Kurs 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 umfassendere Anpassung erfordern, folgen Sie der Anleitung zur Instrumentierung.