Przykładowa aplikacja do kierowania

Ta kategoria testów z narzędziami nie różni się zbytnio od tych kierowanych na zwykłe aplikacje na Androida. Warto zauważyć, że aplikacja testowa, która zawiera instrumentację, musi być podpisana tym samym certyfikatem co aplikacja, na którą jest kierowana.

W tym przewodniku zakładamy, że masz już pewną wiedzę na temat przepływu pracy w drzewie źródeł platformy. Jeśli tak nie jest, zapoznaj się z wymaganiami. W tym przykładzie omawiamy tworzenie nowego testu pomiarowego z docelowym zestawem pakietów ustawionym na własny pakiet aplikacji testowej. Jeśli nie znasz tego zagadnienia, przeczytaj wprowadzenie do testowania platformy.

W tym przewodniku jako przykład użyto tego testu:

  • frameworks/base/packages/Shell/tests

Zanim przejdziesz dalej, możesz najpierw przejrzeć kod, żeby uzyskać ogólne informacje.

Wybierz lokalizację źródłową

Ponieważ test instrumentacji będzie kierowany na aplikację, zgodnie z konwencją należy umieścić kod źródłowy testu w katalogu tests w katalogu głównym katalogu źródłowego komponentu w drzewie źródłowym platformy.

Więcej informacji o lokalizacji źródła znajdziesz w pełnym przykładzie testów samoinstruowania.

Plik manifestu

Podobnie jak w przypadku zwykłej aplikacji, każdy moduł testów instrumentacji wymaga pliku manifestu. Jeśli nadasz plikowi nazwę AndroidManifest.xml i przekażesz go jako Android.mk dla testowego modułu, zostanie on automatycznie uwzględniony w pliku make BUILD_PACKAGE.

Przed dalszymi działaniami zdecydowanie zalecamy zapoznanie się z omówieniem pliku manifestu aplikacji.

Przedstawiamy podstawowe komponenty pliku manifestu i ich funkcje.

Najnowszą wersję pliku manifestu dla przykładowej zmiany w gerrit można znaleźć tutaj: https://android.googlesource.com/platform/frameworks/base/+/main/packages/Shell/tests/AndroidManifest.xml

Dla wygody użytkownika zamieszczamy tutaj zrzut ekranu:

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

Wybrane uwagi dotyczące pliku manifestu:

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

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

Ponieważ jest to pakiet aplikacji testowej, niezależny od testowanego pakietu aplikacji, musisz użyć innej nazwy pakietu. Jedną z częstych konwencji jest dodanie sufiksu .test.

Co więcej, atrybut package jest taki sam jak zwracany przez ComponentName#getPackageName(), a także taki sam, którego używasz do interakcji z różnymi podkomendami pm za pomocą adb shell.

Pamiętaj też, że chociaż nazwa pakietu zwykle ma taki sam styl jak nazwa pakietu Javy, w rzeczywistości ma niewiele wspólnego. Innymi słowy, pakiet aplikacji (lub testu) może zawierać klasy o dowolnych nazwach pakietów, ale z drugiej strony możesz postawić na prostotę i użyć w aplikacji lub teście nazwy pakietu Java na najwyższym poziomie identycznej z nazwą pakietu aplikacji.

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

Jest to wymagane w przypadku wszystkich testów instrumentacji, ponieważ powiązane klasy są zapakowane w oddzielnym pliku biblioteki JAR platformy, co wymaga dodatkowych wpisów w ścieżce klasy, gdy pakiet testów jest wywoływany przez platformę aplikacji.

android:targetPackage="com.android.shell"

Ustawia pakiet docelowy instrumentacji na com.android.shell. Gdy instrumentacja zostanie wywołana za pomocą polecenia am instrument, framework ponownie uruchomi proces com.android.shell i wstrzyknie do niego kod instrumentacji na potrzeby wykonania testu. Oznacza to też, że kod testowy będzie miał dostęp do wszystkich instancji klasy działających w testowanej aplikacji i może manipulować stanem w zależności od dostępnych haka testowego.

Prosty plik konfiguracji

Każdy nowy moduł testowy musi mieć plik konfiguracji, który kieruje system 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 na podstawie Soong. Szczegółowe informacje znajdziesz w sekcji Prosta konfiguracja testu.

Złożony plik konfiguracji

W przypadku bardziej złożonych testów musisz też utworzyć plik konfiguracji testu dla testowego zestawu narzędzi Androida, Trade Federation.

Konfiguracja testu może określać specjalne opcje konfiguracji urządzenia i domyślne argumenty dostarczające klasę testową.

Najnowszą wersję pliku konfiguracyjnego przykładowej zmiany w gerrite można znaleźć w folderze: frameworks/base/packages/Shell/tests/AndroidTest.xml

Dla wygody użytkownika zamieszczamy tutaj zrzut ekranu:

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

Uwagi na temat testowego pliku konfiguracji:

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

Dzięki temu federacja handlowa powinna zainstalować plik ShellTests.apk na urządzeniu docelowym za pomocą określonego atrybutu target_preparer. W ramach usługi Trade Federation deweloperzy mają do dyspozycji wiele narzędzi do przygotowywania urządzeń, które można wykorzystać do sprawdzenia, czy urządzenie jest prawidłowo skonfigurowane przed wykonaniem testu.

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

Określa klasę testu Trade Federation, której należy użyć do wykonania testu, oraz przekazuje pakiet na urządzenie, na którym ma być wykonany, oraz testowy framework, którym w tym przypadku jest JUnit.

Więcej informacji o konfiguracjach testowych modułów

Funkcje JUnit4

Użycie biblioteki android-support-test jako mechanizmu uruchamiania testów umożliwia stosowanie nowych klas testowych w stylu JUnit4, a przykładowa zmiana gerrit obejmuje podstawowe zastosowania jej funkcji.

Najnowszy kod źródłowy przykładowej zmiany w gerrit jest dostępny pod adresem: frameworks/base/packages/Shell/tests/src/com/android/shell/BugreportReceiverTest.java

Chociaż wzorce testowania są zwykle specyficzne dla zespołów komponentów, istnieją pewne wzorce, które są przydatne na ogół.

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

Znacząca różnica w JUnit4 polega na tym, że testy nie muszą już dziedziczyć ze wspólnej klasy testowej. Zamiast tego testujesz je w zwykłych klasach Javy i używasz adnotacji do wskazywania określonych konfiguracji i ograniczeń testów. W tym przykładzie wskazujemy, że ta klasa powinna być uruchamiana jako test JUnit4 na Androida.

Adnotacja @SmallTest określa rozmiar testu dla całej klasy testu: wszystkie metody testu dodane do tej klasy testu dziedziczą tę adnotację rozmiaru testu. Przygotowanie klasy testu przed testem, rozmontowanie po teście i rozmontowanie klasy testu po teście: podobne do metod setUptearDown w JUnit4. Adnotacja Test służy do adnotowania rzeczywistego testu.

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

Adnotacja @Before jest używana przez JUnit4 w metodach do konfigurowania wstępnego testowania. W tym przykładzie nie jest używany, ale @After służy do testowania po demontażu. Analogicznie adnotacje @BeforeClass@AfterClass mogą być używane w metodach JUnit4 do konfiguracji przed wykonaniem wszystkich testów w klasie testów, a potem do jej demontażu. Pamiętaj, że metody konfiguracji i rozwiązywania na poziomie klasy muszą być statyczne.

W odróżnieniu od wcześniejszych wersji JUnit nazwy metod testów nie muszą już zaczynać się od test. Każda z nich musi być opatrzona adnotacją @Test. Tradycyjnie metody testowania muszą być publiczne, zadeklarować brak wartości zwrotnej, nie uwzględniać żadnych parametrów i mogą zgłaszać wyjątki.

        Context context = InstrumentationRegistry.getTargetContext();

Testy JUnit4 nie wymagają już wspólnej klasy bazowej, więc nie trzeba już uzyskiwać instancji Context za pomocą getContext() ani getTargetContext() za pomocą metod klasy bazowej. Nowy testujący zarządza nimi za pomocą InstrumentationRegistry, gdzie przechowywany jest kontekst i ustawienia środowiska utworzone przez ramy pomiarowe. W ramach tego zajęć możesz też wywoływać:

  • getInstrumentation(): wystąpienie do klasy Instrumentation
  • getArguments(): argumenty wiersza poleceń przekazane do am instrument za pomocą -e <key> <value>

Kompilowanie i testowanie lokalnie

W przypadku najczęstszych zastosowań użyj poświadczenia.

W bardziej skomplikowanych przypadkach wymagających bardziej zaawansowanej personalizacji postępuj zgodnie z instrukcjami dotyczącymi implementacji.