Przykład testów samoprzyrządowania

Zadbaj o dobrą organizację dzięki kolekcji Zapisuj i kategoryzuj treści zgodnie ze swoimi preferencjami.

Po uruchomieniu testu oprzyrządowania jego pakiet docelowy jest ponownie uruchamiany z wstrzykniętym kodem oprzyrządowania i zainicjowanym do wykonania. Jedynym wyjątkiem jest to, że pakietem docelowym nie może być sam framework aplikacji Android, czyli pakiet android , ponieważ doprowadziłoby to do paradoksalnej sytuacji, w której musiałby zostać zrestartowany framework Androida, co wspiera funkcje systemu, w tym oprzyrządowanie samo.

Oznacza to, że test instrumentacji nie może zostać wstrzyknięty do platformy Androida, czyli serwera systemowego, w celu wykonania. Aby przetestować platformę systemu Android, kod testowy może wywoływać tylko publiczne powierzchnie interfejsu API lub te, które są udostępniane za pośrednictwem interfejsu AIDL języka definicji interfejsu systemu Android dostępnego w drzewie źródłowym platformy. W przypadku tej kategorii testów kierowanie na konkretny pakiet nie ma sensu. W związku z tym zwyczajowo takie instrumentacje są deklarowane jako docelowe dla własnego pakietu aplikacji testowych, zgodnie z definicją w jego własnym tagu <manifest> AndroidManifest.xml .

W zależności od wymagań pakiety aplikacji testowych z tej kategorii mogą również:

  • Pakiet działań potrzebnych do testowania.
  • Udostępnij identyfikator użytkownika systemowi.
  • Być podpisanym kluczem platformy.
  • Należy skompilować na podstawie źródła platformy, a nie publicznego zestawu SDK.

Ta kategoria testów oprzyrządowania jest czasami określana jako samooprzyrządowanie. Oto kilka przykładów testów samodzielnego oprzyrządowania w źródle platformy:

Opisany tutaj przykład to pisanie nowego testu oprzyrządowania z pakietem docelowym ustawionym we własnym pakiecie aplikacji testowej. W tym przewodniku wykorzystano następujący test jako przykład:

Zaleca się najpierw przejrzeć kod, aby uzyskać przybliżone wrażenie przed kontynuowaniem.

Decydowanie o lokalizacji źródłowej

Zazwyczaj Twój zespół ma już ustalony wzorzec miejsc, w których można sprawdzić kod i miejsca, w których można dodawać testy. Większość zespołów posiada pojedyncze repozytorium git lub udostępnia je innym zespołom, ale ma dedykowany podkatalog, który zawiera kod źródłowy komponentu.

Zakładając, że lokalizacja główna źródła komponentu znajduje się w <component source root> , większość komponentów ma pod sobą foldery src i tests oraz niektóre dodatkowe pliki, takie jak Android.mk (lub podzielone na dodatkowe pliki .mk ), plik manifestu AndroidManifest.xml i plik konfiguracji testu „AndroidTest.xml”.

Ponieważ dodajesz zupełnie nowy tests , prawdopodobnie będziesz musiał utworzyć katalog testing obok twojego komponentu src i wypełnić go treścią.

W niektórych przypadkach Twój zespół może testować dalsze struktury katalogów ze względu na potrzebę spakowania różnych zestawów tests w poszczególnych apkach. W tym przypadku będziesz musiał utworzyć nowy podkatalog w ramach tests .

Niezależnie od struktury, zakończysz wypełnianie katalogu tests lub nowo utworzonego podkatalogu plikami podobnymi do tego, co znajduje się w katalogu instrumentation w przykładowej zmianie gerrita. Poniższe sekcje wyjaśniają dalsze szczegóły każdego pliku.

Plik manifestu

Podobnie jak w przypadku zwykłej aplikacji, każdy moduł testowania oprzyrządowania wymaga pliku manifestu. Jeśli nazwiesz plik jako AndroidManifest.xml i podasz go obok Android.mk dla modułu testowego, zostanie on dołączony automatycznie przez podstawowy plik makefile BUILD_PACKAGE .

Zanim przejdziesz dalej, zdecydowanie zalecamy najpierw zapoznać się z Omówieniem manifestu aplikacji .

Zawiera przegląd podstawowych składników pliku manifestu i ich funkcji. Zobacz przykład pod adresem platform_testing/tests/example/instrumentation/AndroidManifest.xml .

Dla wygody dołączono migawkę:

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

    <application/>

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

</manifest>

Niektórzy wybierają uwagi w pliku manifestu:

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

Atrybut package to nazwa pakietu aplikacji: jest to unikalny identyfikator, którego struktura aplikacji systemu Android używa do identyfikowania aplikacji (lub w tym kontekście: aplikacji testowej). Każdy użytkownik w systemie może zainstalować tylko jedną aplikację o tej nazwie pakietu.

Co więcej, ten atrybut package jest taki sam, jak ComponentName#getPackageName() , a także ten sam, którego użyłbyś do interakcji z różnymi poleceniami podrzędnymi pm za pośrednictwem adb shell .

Należy również zauważyć, że chociaż nazwa pakietu jest zwykle w tym samym stylu, co nazwa pakietu Java, w rzeczywistości ma z nią niewiele wspólnego. Innymi słowy, pakiet aplikacji (lub test) może zawierać klasy z dowolnymi nazwami pakietów, chociaż z drugiej strony możesz zdecydować się na prostotę i mieć nazwę pakietu Java najwyższego poziomu w swojej aplikacji lub test identyczny z nazwą pakietu aplikacji.

android:sharedUserId="android.uid.system"

Oznacza to, że w czasie instalacji ten apk powinien mieć ten sam identyfikator użytkownika, tj. tożsamość środowiska uruchomieniowego, co platforma podstawowa. Zauważ, że zależy to od tego, czy apk jest podpisany tym samym certyfikatem, co platforma podstawowa (zobacz LOCAL_CERTIFICATE w powyższej sekcji), ale są to różne koncepcje:

  • niektóre uprawnienia lub interfejsy API są chronione podpisem, co wymaga tego samego certyfikatu podpisującego
  • niektóre uprawnienia lub interfejsy API wymagają tożsamości użytkownika system wywołującego, co wymaga, aby pakiet wywołujący współdzielił identyfikator użytkownika z system , jeśli jest to oddzielny pakiet od samej platformy podstawowej
<uses-library android:name="android.test.runner" />

Jest to wymagane w przypadku wszystkich testów Instrumentacji, ponieważ powiązane klasy są pakowane w oddzielnym pliku biblioteki jar środowiska, dlatego wymaga dodatkowych wpisów ścieżki klasy, gdy pakiet testowy jest wywoływany przez środowisko aplikacji.

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

Być może zauważyłeś, że targetPackage tutaj jest zadeklarowany tak samo, jak atrybut package zadeklarowany w znaczniku manifest tego pliku. Jak wspomniano w Podstawach testowania , ta kategoria testów oprzyrządowania jest zwykle przeznaczona do testowania interfejsów API frameworka, więc nie ma większego znaczenia, jeśli mają określony pakiet aplikacji docelowej, inny niż on sam.

Prosty plik konfiguracyjny

Każdy nowy moduł testowy musi mieć plik konfiguracyjny kierujący systemem kompilacji z metadanymi modułu, zależnościami czasu kompilacji i instrukcjami pakowania. W większości przypadków wystarcza opcja pliku Blueprint opartego na Soong. Aby uzyskać szczegółowe informacje, zobacz Prosta konfiguracja testowa .

Złożony plik konfiguracyjny

W przypadku tych bardziej złożonych przypadków należy również napisać plik konfiguracyjny testu dla wiązki testowej Androida, Trade Federation .

Konfiguracja testowa może określać specjalne opcje konfiguracji urządzenia i domyślne argumenty, aby dostarczyć klasę testową. Zobacz przykład w /platform_testing/tests/example/instrumentation/AndroidTest.xml .

Dla wygody dołączono migawkę:

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

Niektóre wybierają uwagi dotyczące pliku konfiguracyjnego testu:

<target_preparer class="com.android.tradefed.targetprep.TestAppInstallSetup">
  <option name="test-file-name" value="HelloWorldTests.apk"/>
</target_preparer>

To mówi Federacji Handlowej, aby zainstalowała plik HelloWorldTests.apk na urządzeniu docelowym przy użyciu określonego target_preparer. W Federacji Handlowej dostępnych jest wiele programów przygotowujących cele, które można wykorzystać do zapewnienia prawidłowej konfiguracji urządzenia przed wykonaniem testów.

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

Określa klasę testową Federacji Handlowej, która ma być używana do wykonania testu i przechodzi w pakiecie na urządzeniu, które ma zostać wykonane, oraz framework uruchamiający testy, który w tym przypadku jest JUnit.

Aby uzyskać więcej informacji, zobacz Konfiguracje modułu testowego .

Funkcje JUnit4

Używanie biblioteki android-support-test jako programu uruchamiającego testy umożliwia przyjęcie nowych klas testowych w stylu JUnit4, a przykładowa zmiana gerrit zawiera bardzo podstawowe wykorzystanie jej funkcji. Zobacz przykład w /platform_testing/tests/example/instrumentation/src/android/test/example/helloworld/HelloWorldTest.java .

Chociaż wzorce testowania są zwykle specyficzne dla zespołów komponentów, istnieje kilka ogólnie przydatnych wzorców użycia.

@RunWith(JUnit4.class)
public class HelloWorldTest {

Istotna różnica w JUnit4 polega na tym, że testy nie muszą już dziedziczyć ze wspólnej podstawowej klasy testowej; zamiast tego piszesz testy w zwykłych klasach Javy i używasz adnotacji, aby wskazać określone ustawienia testu i ograniczenia. W tym przykładzie instruujemy, że ta klasa powinna zostać uruchomiona jako test JUnit4.

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

@Before i @After są używane w metodach JUnit4 w celu wykonania konfiguracji przed testem i demontażu po teście. Podobnie adnotacje @BeforeClass i @AfterClass są używane w metodach JUnit4 do przeprowadzenia konfiguracji przed wykonaniem wszystkich testów w klasie testowej, a następnie do usunięcia. Zwróć uwagę, że konfiguracja zakresu klasy i metody rozkładania muszą być statyczne. Jeśli chodzi o metody testowe, w przeciwieństwie do wcześniejszej wersji JUnit, nie muszą już zaczynać nazwy metody od test , zamiast tego każda z nich musi być opatrzona adnotacją @Test . Jak zwykle metody testowe muszą być publiczne, nie deklarować wartości zwracanych, nie przyjmować parametrów i mogą zgłaszać wyjątki.

Ważne : same metody testowe są oznaczone adnotacją @Test ; i zauważ, że aby testy były wykonywane przez APCT, muszą być opatrzone adnotacjami z rozmiarami testów: przykładowa metoda z adnotacjami testHelloWorld jako @SmallTest . Adnotację można zastosować w zakresie metody lub zakresie klasy.

Dostęp do instrumentation

Chociaż nie jest to omówione w podstawowym przykładzie Hello World, dość często test systemu Android wymaga wystąpienia Instrumentation dostępu: jest to podstawowy interfejs API, który zapewnia dostęp do kontekstów aplikacji, testowych interfejsów API związanych z cyklem życia aktywności i nie tylko.

Ponieważ testy JUnit4 nie wymagają już wspólnej klasy bazowej, nie jest już konieczne uzyskiwanie wystąpienia Instrumentation za pośrednictwem InstrumentationTestCase#getInstrumentation() , zamiast tego nowy program uruchamiający testy zarządza nim za pośrednictwem InstrumentationRegistry , gdzie jest przechowywana konfiguracja kontekstowa i środowiskowa utworzona przez platformę instrumentacji.

Aby uzyskać dostęp do instancji klasy Instrumentation , wystarczy wywołać metodę statyczną getInstrumentation() w klasie InstrumentationRegistry :

Instrumentation instrumentation = InstrumentationRegistry.getInstrumentation()

Twórz i testuj lokalnie

W najczęstszych przypadkach użycia użyj Atest .

W przypadku bardziej złożonych przypadków wymagających większego dostosowania postępuj zgodnie z instrukcjami dotyczącymi oprzyrządowania .