Gdy rozpoczyna się test instrumentacji, uruchamia się docelowy pakiet z wstrzykniętym kodem instrumentacji i inicjuje jego wykonanie. Jedynym wyjątkiem jest to, że docelowy pakiet nie może być sam framework aplikacji na Androida, np. pakiet android
, ponieważ prowadzi to do paradoksalnej sytuacji, w której trzeba by ponownie uruchomić framework Androida, który obsługuje funkcje systemu, w tym samą instrumentację.
Oznacza to, że test z instrumentacją nie może się wstrzyknąć do frameworku Androida (czyli serwera systemowego) w celu wykonania. Aby przetestować platformę Android, kod testowy może wywoływać tylko publiczne platformy API lub te udostępnione z użyciem języka AIDL interfejsu Androida dostępnego w drzewie źródłowym platformy. W przypadku tej kategorii testów nie ma sensu kierowanie na konkretny pakiet. Dlatego zwykle takie instrumentacje są deklarowane jako kierowane na własny pakiet aplikacji testowej, jak określono w tagu <manifest>
w elementach AndroidManifest.xml
.
W zależności od wymagań pakiety testowych aplikacji w tej kategorii mogą też:
- Aktywności pakietu potrzebne do testowania.
- Udostępnij identyfikator użytkownika systemowi.
- być podpisane kluczem platformy;
- być skompilowana na podstawie źródła platformy, a nie publicznego pakietu SDK;
Ta kategoria testów jest czasami nazywana autoinstrumentacją. Oto kilka przykładów testów samoobsługowych w źródle platformy:
W tym przykładzie omawiamy tworzenie nowego testu pomiarowego z docelowym pakietem ustawionym na własny pakiet aplikacji testowej. W tym przewodniku jako przykład użyto tego testu:
Zanim przejdziesz dalej, możesz najpierw przejrzeć kod, żeby uzyskać ogólne informacje.
Wybierz lokalizację źródłową
Zespół ma zwykle ustalony schemat miejsc, w których należy sprawdzić kod, oraz miejsc, w których należy dodać testy. Większość zespołów ma jedno repozytorium Git lub udostępnia je innym zespołom, ale ma specjalny podkatalog, który zawiera kod źródłowy komponentów.
Zakładając, że główna lokalizacja źródła komponentu znajduje się w lokalizacji <component source
root>
, większość komponentów ma podfoldery src
i tests
oraz kilka dodatkowych plików, np. Android.mk
(lub podzielonych na dodatkowe pliki .mk
), pliku manifestu AndroidManifest.xml
i testowego pliku konfiguracji „AndroidTest.xml”.
Ponieważ dodajesz zupełnie nowy test, prawdopodobnie musisz utworzyć katalog tests
obok komponentu src
i wypełnić go treścią.
W niektórych przypadkach Twój zespół może mieć dodatkowe struktury katalogów w folderze tests
ze względu na konieczność spakowania różnych zestawów testów do poszczególnych plików APK. W tym przypadku musisz utworzyć nowy katalog podrzędny w folderze tests
.
Bez względu na strukturę wypełniasz katalog tests
lub nowo utworzony podkatalog plikami podobnymi do plików znajdujących się w katalogu instrumentation
w przykładowej zmianie gerrit. Szczegóły dotyczące każdego pliku znajdziesz w dalszej części tego dokumentu.
Plik manifestu
Podobnie jak w przypadku projektu aplikacji, każdy moduł testu instrumentacji wymaga pliku manifestu o nazwie AndroidManifest.xml
. Aby automatycznie uwzględnić ten plik za pomocą pliku makecoreBUILD_PACKAGE
, podaj go obok pliku Android.mk
dla modułu testowego.
Jeśli nie znasz pliku AndroidManifest.xml
, zapoznaj się z artykułem Omówienie pliku manifestu aplikacji.
Oto 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>
Wybrane uwagi dotyczące 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 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.
Co więcej, ten atrybut package
jest taki sam jak ten zwracany przez ComponentName#getPackageName()
, a także ten, którego używasz do interakcji z różnymi podkomendami pm
, które używają atrybutu adb shell
.
Pamiętaj, że chociaż nazwa pakietu jest zwykle w tym samym stylu co nazwa pakietu Java, w istocie ma niewiele wspólnego z pakietami Java. Inaczej mówiąc, pakiet aplikacji (lub testu) może zawierać klasy z dowolnymi nazwami pakietów, jednak dla uproszczenia możesz wybrać taki pakiet, w którym nazwa najwyższego poziomu w Javie będzie taka sama jak nazwa pakietu aplikacji, lub taka sama w teście.
android:sharedUserId="android.uid.system"
Oznacza to, że w momencie instalacji plik APK powinien mieć ten sam identyfikator użytkownika, czyli tożsamość w czasie wykonywania, co platforma główna. Pamiętaj, że zależy to od tego, czy plik APK jest podpisany tym samym certyfikatem co platforma główna (patrz LOCAL_CERTIFICATE
w poprzedniej sekcji), ale są to różne koncepcje:
- niektóre uprawnienia lub interfejsy API są chronione podpisem, co wymaga użycia tego samego certyfikatu podpisywania
- niektóre uprawnienia lub interfejsy API wymagają tożsamości użytkownika
system
, co oznacza, że pakiet wywołujący musi udostępnić identyfikator użytkownika usłudzesystem
, jeśli jest to pakiet oddzielony od 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 platformy, co wymaga dodatkowych wpisów ścieżki klasy, gdy pakiet testów jest wywoływany przez platformę aplikacji.
android:targetPackage="android.test.example.helloworld"
Zauważysz pewnie, że atrybut targetPackage
jest tu zadeklarowany tak samo jak atrybut package
w tagu manifest
w tym pliku. Jak wspomniano w podstawach testowania, ta kategoria testów jest zwykle przeznaczona do testowania interfejsów API frameworków, więc nie ma większego znaczenia, czy testy są kierowane na konkretny pakiet aplikacji.
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 artykule Prosta konfiguracja testu.
Złożony plik konfiguracji
W tych bardziej złożonych przypadkach musisz też napisać testowy plik konfiguracyjny dla jarzma testowego na Androida – federacji handlowej.
Konfiguracja testu może określać specjalne opcje konfiguracji urządzenia i domyślne argumenty, które mają być przekazywane do klasy testu. Przykładowy plik znajdziesz w folderze /platform_testing/tests/example/instrumentation/AndroidTest.xml.
Dla wygody podajemy tu podsumowanie:
<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>
Oto kilka uwag na temat pliku konfiguracji testu:
<target_preparer class="com.android.tradefed.targetprep.TestAppInstallSetup">
<option name="test-file-name" value="HelloWorldTests.apk"/>
</target_preparer>
To polecenie mówi Trade Federation, aby zainstalowała plik HelloWorldTests.apk na urządzeniu docelowym za pomocą określonego narzędzia 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="android.test.example.helloworld"/>
<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 znajdziesz w artykule o konfiguracjach testowych modułów.
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 wykorzystanie jej funkcji. Przykład znajdziesz w pliku /platform_testing/tests/example/instrumentation/src/android/test/example/helloworld/HelloWorldTest.java.
Chociaż wzorce testowania są zwykle specyficzne dla zespołów komponentów, istnieją pewne wzorce, które są przydatne na ogół.
@RunWith(JUnit4.class)
public class HelloWorldTest {
Istotną różnicą w JUnit4 jest to, że testy nie muszą już dziedziczyć z ogólnej klasy testów podstawowych. 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.
@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 przeprowadzania konfiguracji przed testem i po jego zakończeniu. Podobnie adnotacje @BeforeClass
i @AfterClass
są używane w metodach przez 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 przypadku metod testów w przeciwieństwie do wcześniejszej wersji JUnit nazwy metod nie muszą już zaczynać się od test
. Każda z nich musi być oznaczona adnotacją @Test
. Tradycyjnie metody testów muszą być publiczne, zadeklarować brak wartości zwrotnej, nie mogą przyjmować żadnych parametrów i mogą zgłaszać wyjątki.
Dostęp do klasy pomiarowej
Chociaż nie jest to opisane w podstawowym przykładzie „hello world”, testy na Androidzie często wymagają dostępu do instancji Instrumentation
: to podstawowy interfejs API, który zapewnia dostęp do kontekstów aplikacji, interfejsów testowych związanych z cyklem życia aktywności i innych elementów.
Testy JUnit4 nie wymagają już wspólnej klasy bazowej, więc nie trzeba uzyskiwać instancji Instrumentation
za pomocą InstrumentationTestCase#getInstrumentation()
. Nowy testujący zarządza nią za pomocą InstrumentationRegistry
, gdzie przechowywany jest kontekst i ustawienia środowiska utworzone przez framework pomiarowy.
Aby uzyskać dostęp do instancji klasy Instrumentation
, po prostu wywołaj stałą metodę getInstrumentation()
w klasie InstrumentationRegistry
:
Instrumentation instrumentation = InstrumentationRegistry.getInstrumentation()
Kompilowanie i testowanie lokalnie
W przypadku najczęstszych zastosowań użyj poświadczenia.
W bardziej złożonych przypadkach, które wymagają większych dostosowań, postępuj zgodnie z instrukcjami dotyczącymi instrumentów.