Przykład testów samoinstrumentujących

Po rozpoczęciu testu oprzyrządowania jego pakiet docelowy jest uruchamiany ponownie z wstrzykniętym kodem oprzyrządowania i inicjowaniem jego wykonania. Jedynym wyjątkiem jest to, że pakietem docelowym nie może być sam framework aplikacji Android, taki jak pakiet android , ponieważ prowadzi to do paradoksalnej sytuacji, w której konieczne byłoby ponowne uruchomienie frameworku Android, który obsługuje funkcje systemu, w tym samego instrumentarium.

Oznacza to, że test oprzyrządowania nie może zostać wstrzyknięty do środowiska Androida, czyli serwera systemowego, w celu wykonania. Aby przetestować platformę Android, kod testowy może wywoływać tylko publiczne powierzchnie API lub te udostępniane przy użyciu języka AIDL interfejsu definicji interfejsu Android dostępnego w drzewie źródłowym platformy. W przypadku tej kategorii testów nie ma sensu skupiać się na konkretnym pakiecie. Dlatego zwyczajowo deklaruje się, że takie instrumentacje są przeznaczone dla własnego pakietu aplikacji testowej, zgodnie z definicją we własnym tagu <manifest> pliku AndroidManifest.xml .

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

  • Połącz działania potrzebne do testowania.
  • Udostępnij identyfikator użytkownika systemowi.
  • Podpisz się kluczem platformy.
  • Należy skompilować w oparciu o źródło platformy, a nie publiczny zestaw SDK.

Ta kategoria testów oprzyrządowania jest czasami nazywana samodzielnym oprzyrządowaniem. Oto kilka przykładów testów samodzielnego oprzyrządowania w źródle platformy:

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

Zaleca się najpierw przejrzeć kod, aby uzyskać ogólne wrażenie przed kontynuowaniem.

Zdecyduj się na lokalizację źródłową

Zazwyczaj Twój zespół będzie już miał ustalony wzorzec miejsc do sprawdzania kodu i miejsc do dodawania testów. Większość zespołów posiada jedno repozytorium git lub udostępnia je innym zespołom, ale ma dedykowany podkatalog zawierający kod źródłowy komponentu.

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

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

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

Niezależnie od struktury, w końcu zapełnisz katalog tests lub nowo utworzony podkatalog plikami podobnymi do tego, co znajduje się w katalogu instrumentation w przykładowej zmianie gerrit. Szczegóły każdego pliku wyjaśniono w dalszej części tego dokumentu.

Plik manifestu

Podobnie jak w przypadku projektu aplikacji, każdy moduł testowy oprzyrządowania wymaga pliku manifestu o nazwie AndroidManifest.xml . Aby automatycznie dołączyć ten plik przy użyciu podstawowego pliku makefile BUILD_PACKAGE , podaj ten plik obok pliku Android.mk dla modułu testowego.

Jeśli nie znasz pliku AndroidManifest.xml , zapoznaj się z omówieniem manifestu aplikacji

Poniżej znajduje się przykładowy plik AndroidManifest.xml :

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

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

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

</manifest>

Niektóre wybrane uwagi na temat 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 używany przez platformę aplikacji systemu Android 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 zwracany przez ComponentName#getPackageName() , a także ten sam, którego można używać do interakcji z różnymi podpoleceniami pm za pomocą adb shell .

Zauważ, że chociaż nazwa pakietu jest zazwyczaj w tym samym stylu, co nazwa pakietu Java, w rzeczywistości ma z nią niewiele wspólnego. Innymi słowy, pakiet Twojej aplikacji (lub testu) może zawierać klasy o dowolnych nazwach pakietów, chociaż z drugiej strony możesz zdecydować się na prostotę i mieć w aplikacji lub teście nazwę pakietu Java najwyższego poziomu identyczną z nazwą pakietu aplikacji.

android:sharedUserId="android.uid.system"

Oznacza to, że w czasie instalacji plik APK powinien otrzymać ten sam identyfikator użytkownika, tj. tożsamość wykonawczą, co platforma podstawowa. Pamiętaj, że zależy to od tego, czy apk jest podpisany tym samym certyfikatem co platforma podstawowa (patrz LOCAL_CERTIFICATE w poprzedniej sekcji), ale są to różne koncepcje:

  • niektóre uprawnienia lub interfejsy API są chronione podpisem, co wymaga tego samego certyfikatu podpisywania
  • niektóre uprawnienia lub interfejsy API wymagają tożsamości użytkownika system wywołującego, co wymaga, aby pakiet wywołujący udostępniał system identyfikator użytkownika, jeśli jest to pakiet oddzielny 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ą spakowane w oddzielnym pliku biblioteki JAR platformy, dlatego wymagane są dodatkowe wpisy ścieżki klas, gdy pakiet testowy jest wywoływany przez platformę aplikacji.

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

Być może zauważyłeś, że pakiet targetPackage jest tutaj zadeklarowany tak samo, jak atrybut package zadeklarowany w znaczniku manifest tego pliku. Jak wspomniano w temacie Podstawy testowania , ta kategoria testów oprzyrządowania jest zazwyczaj przeznaczona do testowania interfejsów API platformy, więc posiadanie przez nie konkretnego docelowego pakietu aplikacji, innego niż on sam, nie jest dla nich zbyt istotne.

Prosty plik konfiguracyjny

Każdy nowy moduł testowy musi mieć plik konfiguracyjny, który będzie sterował systemem kompilacji za pomocą metadanych modułu, zależności w czasie kompilacji i instrukcji pakowania. W większości przypadków wystarczająca jest opcja pliku Blueprint oparta na Song. Aby uzyskać szczegółowe informacje, zobacz Prosta konfiguracja testu .

Złożony plik konfiguracyjny

W bardziej złożonych przypadkach należy także 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 dostarczające 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>

Kilka wybranych uwag na temat testowego pliku konfiguracyjnego:

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

To informuje Federację Handlową, aby zainstalowała plik HelloWorldTests.apk na urządzeniu docelowym przy użyciu określonego narzędzia target_preparer. Programiści w Federacji Handlowej mają do dyspozycji wiele narzędzi do przygotowywania celów, które można wykorzystać w celu zapewnienia prawidłowej konfiguracji urządzenia przed wykonaniem testu.

<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 zostać użyta do wykonania testu i przechodzi w pakiecie na urządzeniu, które ma zostać wykonane, oraz strukturę modułu uruchamiającego testy, którą w tym przypadku jest JUnit.

Aby uzyskać więcej informacji, zobacz Konfiguracje modułów testowych .

Funkcje JUnit4

Użycie biblioteki android-support-test jako modułu uruchamiającego testy umożliwia przyjęcie nowych klas testowych w stylu JUnit4, a przykładowa zmiana gerrita obejmuje 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 składowych, istnieją pewne ogólnie przydatne wzorce 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 Java i używasz adnotacji, aby wskazać konkretną konfigurację 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() {
    ...

Adnotacje @Before i @After są używane w metodach JUnit4 do wykonywania konfiguracji przed testem i demontażu po teście. Podobnie adnotacje @BeforeClass i @AfterClass są używane w metodach JUnit4 w celu przeprowadzenia konfiguracji przed wykonaniem wszystkich testów w klasie testowej, a następnie jej usunięcia. Należy pamiętać, że metody konfiguracji i usuwania zakresu klasy muszą być statyczne. Jeśli chodzi o metody testowe, w przeciwieństwie do wcześniejszych wersji JUnit, nie muszą one już rozpoczynać 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 zwracanej, nie przyjmować żadnych parametrów i mogą zgłaszać wyjątki.

Dostęp do klasy oprzyrządowania

Chociaż nie jest to omówione w podstawowym przykładzie hello world, dość często zdarza się, że test Androida wymaga dostępu do instancji Instrumentation : 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 instancji Instrumentation za pośrednictwem InstrumentationTestCase#getInstrumentation() , zamiast tego nowy moduł uruchamiający testy zarządza nią za pośrednictwem InstrumentationRegistry , gdzie przechowywane są ustawienia kontekstowe i środowiskowe utworzone przez platformę instrumentacji.

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

Instrumentation instrumentation = InstrumentationRegistry.getInstrumentation()

Kompiluj 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 należy postępować zgodnie z instrukcjami dotyczącymi oprzyrządowania .