Przykład kierowania na aplikację

Ta kategoria testów z instrumentacją nie różni się zbytnio od testów kierowanych na zwykłe aplikacje na Androida. Warto pamiętać, że testowa aplikacja zawierająca 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 nie, zapoznaj się z wymaganiami. W tym przykładzie omawiamy tworzenie nowego testu pomiarowego z ustawionym zestawem docelowym w ramach własnego pakietu aplikacji testowej. Jeśli nie znasz tego zagadnienia, przeczytaj wprowadzenie do testowania platformy.

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

  • frameworks/base/packages/Shell/tests

Przed kontynuacją zalecamy przejrzenie kodu, aby uzyskać ogólne pojęcie o jego zawartości.

Wybierz lokalizację źródłową

Testowanie pomiarów będzie kierowane na aplikację, dlatego zgodnie z konwencją kod źródłowy testu należy umieścić 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.

Znajdziesz tu omówienie podstawowych elementów pliku manifestu i ich funkcji.

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

Dla wygody użytkownika zamieszczamy 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 testowy pakiet aplikacji, 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 jest zwykle w tym samym stylu co nazwa pakietu Java, w istocie ma z nią 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 Instrumentation, ponieważ powiązane klasy są pakowane w oddzielnym pliku biblioteki JAR platformy, co wymaga dodatkowych wpisów classpath, gdy pakiet testów jest wywoływany przez platformę aplikacji.

android:targetPackage="com.android.shell"

W ten sposób ustawiasz docelowy pakiet narzędzi 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 testu będzie miał dostęp do wszystkich instancji klasy uruchomionych w testowanej aplikacji i może manipulować stanem w zależności od dostępnych haka testów.

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. Więcej informacji znajdziesz w sekcji Prosta konfiguracja testu.

złożony plik konfiguracji,

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

Konfiguracja testu może określać specjalne opcje konfiguracji urządzenia i domyślne argumenty do przekazania klasie testu.

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

Oto kilka wybranych uwag na temat pliku konfiguracji testu:

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

To powoduje, że Trade Federation instaluje plik ShellTests.apk na urządzeniu docelowym za pomocą określonego parametru target_preparer. W ramach 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 modułu testowego

Funkcje JUnit4

Korzystanie z biblioteki android-support-test jako test runnera umożliwia stosowanie nowych klas testów w stylu JUnit4, a przykładowa zmiana w gerrit zawiera bardzo podstawowe użycie 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 {

Istotną różnicą w JUnit4 jest to, że testy nie muszą już dziedziczyć po wspólnej podstawowej klasie testów. Zamiast tego piszesz testy w zwykłych klasach Java i używasz adnotacji, aby wskazać określone ustawienia testu i ograniczenia. 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 w metodach przez JUnit4 do konfiguracji wstępnej testu. 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. Jak zwykle metody testów muszą być publiczne, nie mogą deklarować wartości zwracanej, nie mogą przyjmować 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 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(): instancja 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 złożonych przypadkach wymagających bardziej zaawansowanej personalizacji postępuj zgodnie z instrukcjami dotyczącymi implementacji.