Beispiel für selbstinstrumentierende Tests

Wenn ein Instrumentierungstest gestartet wird, wird sein Zielpaket mit injiziertem Instrumentierungscode neu gestartet und zur Ausführung initiiert. Eine Ausnahme ist , dass das Ziel - Paket hier nicht die Android Application Framework selbst, dh das Paket android , da dies zu der paradoxen Situation führen würde , wo Android Rahmen benötigen würde neu gestartet werden, das ist das, was die Systemfunktionen unterstützt, einschließlich der Instrumentierung selbst.

Dies bedeutet, dass sich ein Instrumentierungstest nicht zur Ausführung in das Android-Framework, auch bekannt als Systemserver, einschleusen kann. Um die Android Framework zu testen, kann der Test - Code nur öffentliche API Oberflächen aufrufen, oder solche , die über Android Interface Definition Language ausgesetzt AIDL in der Plattform - Source - Tree. Für diese Kategorie von Tests ist es nicht sinnvoll, auf ein bestimmtes Paket abzuzielen. Daher ist es üblich , für solche Instrumentierungen zu erklären , um sein eigenes Testanwendungspaketes Ziel, wie es in seiner eigenen definiert <manifest> -Tag von AndroidManifest.xml .

Je nach Anforderung können Testanwendungspakete dieser Kategorie auch:

  • Bündeln Sie Aktivitäten, die für das Testen erforderlich sind.
  • Teilen Sie die Benutzer-ID mit dem System.
  • Mit dem Plattformschlüssel signiert sein.
  • Kompiliert werden gegen die Framework-Quelle und nicht gegen das öffentliche SDK.

Diese Kategorie von Instrumentierungstests wird manchmal als Selbstinstrumentierung bezeichnet. Hier sind einige Beispiele für Selbstinstrumentierungstests in der Plattformquelle:

Das hier behandelte Beispiel ist das Schreiben eines neuen Instrumentierungstests, wobei das Zielpaket in seinem eigenen Testanwendungspaket festgelegt ist. In diesem Leitfaden wird der folgende Test als Beispiel verwendet:

Es wird empfohlen, zuerst den Code zu durchsuchen, um sich einen groben Eindruck zu verschaffen, bevor Sie fortfahren.

Entscheidung für einen Quellort

In der Regel verfügt Ihr Team bereits über ein festgelegtes Muster von Orten zum Einchecken von Code und Orten zum Hinzufügen von Tests. Die meisten Teams besitzen ein einzelnes Git-Repository oder teilen eines mit anderen Teams, haben jedoch ein dediziertes Unterverzeichnis, das den Quellcode der Komponenten enthält.

Unter der Annahme , das Stammverzeichnis für die Komponentenquelle ist bei <component source root> , die meisten Komponenten src und tests Ordner unter ihm, und einige zusätzliche Dateien wie Android.mk (oder aufgebrochen in zusätzliche .mk - Dateien), die Manifest - Datei AndroidManifest.xml , und die Testkonfigurationsdatei ‚AndroidTest.xml‘.

Da Sie einen brandneuen Test hinzufügen, müssen Sie wahrscheinlich das erstellen tests Verzeichnis neben Ihrer Komponente src , und es mit Inhalt zu füllen.

In einigen Fällen kann Ihr Team weiter haben Verzeichnisstrukturen unter tests aufgrund der Notwendigkeit , verschiedene Suiten von Tests in einzelne APKs zu verpacken. Und in diesem Fall, müssen Sie ein neues Unterverzeichnis unter erstellen tests .

Unabhängig von der Struktur, werden Sie das Bevölkern am Ende tests Verzeichnis oder das neu erstellte Unterverzeichnis mit Dateien ähnlich zu dem, was in instrumentation Verzeichnis in der Probe gerrit ändern. In den folgenden Abschnitten werden weitere Details zu jeder Datei erläutert.

Manifestdatei

Genau wie eine normale Anwendung benötigt jedes Instrumentationstestmodul eine Manifestdatei. Wenn Sie die Datei als Namen AndroidManifest.xml und bieten sich neben Android.mk für Ihren Testmodul, wird es automatisch vom bekommen enthält BUILD_PACKAGE Kern Make - Datei.

Bevor Sie fortfahren, ist es sehr empfehlenswert durch die gehen App Manifest Übersicht zuerst.

Dies gibt einen Überblick über die grundlegenden Komponenten einer Manifestdatei und deren Funktionalitäten. Siehe Beispiel bei platform_testing / Tests / example / Instrumentierung / AndroidManifest.xml .

Der Einfachheit halber ist hier ein Schnappschuss enthalten:

<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="android.test.example.helloworld" >

    <uses-sdk android:minSdkVersion="21" android:targetSdkVersion="21" />

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

    <instrumentation android:name="android.support.test.runner.AndroidJUnitRunner"
                     android:targetPackage="android.test.example.helloworld"
                     android:label="Hello World Test"/>

</manifest>

Einige ausgewählte Anmerkungen zur Manifestdatei:

<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="android.test.example.helloworld" >

Das package Attribut ist das Anwendungspaket Name: Dies ist die eindeutige Kennung , dass die Android Application Framework Anwendungen eine Anwendung zu identifizieren (oder in diesem Zusammenhang: Testanwendung). Jeder Benutzer im System kann nur eine Anwendung mit diesem Paketnamen installieren.

Darüber hinaus dieses package ist Attribut das gleiche wie das, was ComponentName#getPackageName() zurückkehrt, und auch die gleiche Sie mit verschiedenen zu interagieren würde pm Unterbefehle über adb shell .

Bitte beachten Sie auch, dass der Paketname zwar normalerweise den gleichen Stil wie ein Java-Paketname hat, aber nur sehr wenige Dinge damit zu tun hat. Mit anderen Worten, Ihr Anwendungs- (oder Test-)Paket kann Klassen mit beliebigen Paketnamen enthalten, obwohl Sie sich andererseits der Einfachheit halber entscheiden und Ihren Java-Paketnamen der obersten Ebene in Ihrer Anwendung oder Ihrem Test identisch mit dem Anwendungspaketnamen verwenden können.

android:sharedUserId="android.uid.system"

Dies erklärt, dass dieser APK zum Zeitpunkt der Installation die gleiche Benutzer-ID, dh Laufzeitidentität, wie der Kernplattform gewährt werden sollte. Beachten Sie, dass dies auf der apk abhängt mit demselben Zertifikat als Kern Plattform Unterzeichnung (siehe LOCAL_CERTIFICATE in Abschnitt oben), doch sind sie unterschiedliche Konzepte:

  • einige Berechtigungen oder APIs sind signaturgeschützt, was das gleiche Signaturzertifikat erfordert
  • einige Berechtigungen oder APIs erfordert die system des Anrufers, die die anrufende Paket zu teilen Benutzer - ID mit erfordert system , wenn es sich um ein separates Paket von Core - Plattform ist selbst
<uses-library android:name="android.test.runner" />

Dies ist für alle Instrumentationstests erforderlich, da die zugehörigen Klassen in einer separaten Framework-JAR-Bibliotheksdatei verpackt sind und daher zusätzliche Klassenpfadeinträge erforderlich sind, wenn das Testpaket vom Anwendungsframework aufgerufen wird.

android:targetPackage="android.test.example.helloworld"

Sie haben vielleicht bemerkt , dass die targetPackage hier das gleiche erklärt wird , wie das package Attribut in dem deklarierten manifest - Tag dieser Datei. Wie in der genannte Prüfung Grundlagen , wird diese Kategorie von Instrumenten Test für Test - Framework - APIs typischerweise bestimmt, so ist es nicht sehr sinnvoll für sie ein spezielles gezieltes Anwendungspaket zu haben, andere dann selbst.

Einfache Konfigurationsdatei

Jedes neue Testmodul muss über eine Konfigurationsdatei verfügen, um das Build-System mit Modul-Metadaten, Kompilierzeit-Abhängigkeiten und Verpackungsanweisungen zu leiten. In den meisten Fällen ist die auf Soong basierende Blueprint-Dateioption ausreichend. Weitere Einzelheiten finden Sie einfache Testkonfiguration .

Komplexe Konfigurationsdatei

Für diese komplexeren Fällen müssen Sie auch eine Testkonfigurationsdatei für Android-Test harness, schreiben Trade Federation .

Die Testkonfiguration kann spezielle Geräteeinrichtungsoptionen und Standardargumente angeben, um die Testklasse bereitzustellen. Siehe Beispiel bei /platform_testing/tests/example/instrumentation/AndroidTest.xml .

Der Einfachheit halber ist hier ein Schnappschuss enthalten:

<configuration description="Runs sample instrumentation test.">
  <target_preparer class="com.android.tradefed.targetprep.TestFilePushSetup"/>
  <target_preparer class="com.android.tradefed.targetprep.TestAppInstallSetup">
    <option name="test-file-name" value="HelloWorldTests.apk"/>
  </target_preparer>
  <target_preparer class="com.android.tradefed.targetprep.PushFilePreparer"/>
  <target_preparer class="com.android.tradefed.targetprep.RunCommandTargetPreparer"/>
  <option name="test-suite-tag" value="apct"/>
  <option name="test-tag" value="SampleInstrumentationTest"/>

  <test class="com.android.tradefed.testtype.AndroidJUnitTest">
    <option name="package" value="android.test.example.helloworld"/>
    <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="HelloWorldTests.apk"/>
</target_preparer>

Dies weist Trade Federation an, die HelloWorldTests.apk mit einem angegebenen target_preparer auf dem Zielgerät zu installieren. Entwicklern in der Trade Federation stehen viele Zielvorbereitungsprogramme zur Verfügung, mit denen sichergestellt werden kann, dass das Gerät vor der Testausführung richtig eingerichtet ist.

<test class="com.android.tradefed.testtype.AndroidJUnitTest">
  <option name="package" value="android.test.example.helloworld"/>
  <option name="runner" value="android.support.test.runner.AndroidJUnitRunner"/>
</test>

Dies gibt die Trade Federation-Testklasse an, die verwendet werden soll, um den Test auszuführen und das Paket auf dem auszuführenden Gerät und das Test-Runner-Framework, in diesem Fall JUnit, zu übergeben.

Weitere Informationen finden Sie Testmodul Configs .

JUnit4-Funktionen

Mit android-support-test - Bibliothek als Testläufer ermöglicht Annahme neuer JUnit4 Stil Testklassen und die Probe gerrit Änderung enthält einige sehr einfache Nutzung ihrer Funktionen. Siehe Beispiel bei /platform_testing/tests/example/instrumentation/src/android/test/example/helloworld/HelloWorldTest.java .

Während Testmuster normalerweise spezifisch für Komponententeams sind, gibt es einige allgemein nützliche Nutzungsmuster.

@RunWith(JUnit4.class)
public class HelloWorldTest {

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 JUnit4-Test ausgeführt werden soll.

    @BeforeClass
    public static void beforeClass() {
    ...
    @AfterClass
    public static void afterClass() {
    ...
    @Before
    public void before() {
    ...
    @After
    public void after() {
    ...
    @Test
    @SmallTest
    public void testHelloWorld() {
    ...

Die @Before und @After Annotationen werden auf Methoden , die von JUnit4 verwendet pre Prüfaufbau und Post - Test teardown zuführen. Ähnlich sind die @BeforeClass und @AfterClass sind Anmerkungen zu den Methoden von JUnit4 verwendet Setup ausführen , bevor alle Tests in einer Testklasse ausgeführt werden , und Abrüsten danach. Beachten Sie, dass die Setup- und Teardown-Methoden für den Klassenbereich statisch sein müssen. Wie bei den Testverfahren, anders als in früheren Version von JUnit, sie nicht mehr benötigt den Namen der Methode , mit zu beginnen test , sondern jeder von ihnen muss mit Anmerkungen versehen wird @Test . Wie üblich müssen Testmethoden öffentlich sein, keinen Rückgabewert deklarieren, keine Parameter annehmen und können Ausnahmen auslösen.

Wichtig: Die Prüfmethoden selbst mit Anmerkungen versehen werden @Test Anmerkung; und beachten Sie, dass für die Tests über APCT ausgeführt werden, müssen sie mit Testgrößen mit Anmerkungen versehen werden: Das Beispiel kommentierten Methode testHelloWorld als @SmallTest . Die Annotation kann auf Methodenbereich oder Klassenbereich angewendet werden.

Zugreifen instrumentation

Obwohl nicht in dem Grunde Hallo Welt Beispiel bedeckt, ist es ziemlich üblich , dass ein Android - Test Zugang zu benötigen Instrumentation Beispiel: dies ist die Kern - API - Schnittstelle ist , der Zugriff auf Anwendungskontexte bereitstellt, Aktivität Lifecycle bezogenen Test APIs und vieles mehr.

Da die JUnit4 nicht mehr testet eine gemeinsame Basisklasse benötigt, ist es nicht mehr erforderlich , erhalten Instrumentation Instanz über InstrumentationTestCase#getInstrumentation() statt, die neuen Test Läufer schaffen es über InstrumentationRegistry wo kontextuelle und Umwelt Setup durch Instrumentierung Rahmen gespeichert wird erstellt.

Um die Instanz zugreifen Instrumentation Klasse, rufen Sie einfach statische Methode getInstrumentation() auf InstrumentationRegistry Klasse:

Instrumentation instrumentation = InstrumentationRegistry.getInstrumentation()

Lokal bauen und testen

Für die häufigsten Anwendungsfälle beschäftigen Atest .

Für komplexere Fälle schwere Anpassung erfordern, befolgen Sie die Instrumentierung Anweisungen .