Ten samouczek przeprowadzi Cię przez proces tworzenia konfiguracji testowej „hello world” Federacji Handlowej (TF) i zapewni praktyczne wprowadzenie do frameworka TF. Zaczynając od środowiska programistycznego stworzysz prostą konfigurację i dodasz funkcje.
Samouczek przedstawia proces tworzenia testów jako zestaw ćwiczeń, z których każde składa się z kilku kroków, które demonstrują, jak budować i stopniowo udoskonalać konfigurację. Podany jest cały przykładowy kod potrzebny do ukończenia konfiguracji testu, a tytuł każdego ćwiczenia jest oznaczony literą opisującą role związane z tym krokiem:
- D dla programisty
- Ja dla Integratora
- R jak biegacz testowy
Po ukończeniu samouczka będziesz miał działającą konfigurację TF i zrozumiesz wiele ważnych pojęć we frameworku TF.
Zakładanie Federacji Handlowej
Aby uzyskać szczegółowe informacje na temat konfigurowania środowiska programistycznego TF, zobacz Konfiguracja maszyny . Reszta tego samouczka zakłada, że masz otwartą powłokę, która została zainicjowana w środowisku TF.
Dla uproszczenia ten samouczek ilustruje dodawanie konfiguracji i jej klas do podstawowej biblioteki TF Framework. Można to rozszerzyć na programowanie modułów poza drzewem źródłowym, kompilując plik JAR ze źródłem handlu, a następnie kompilując moduły na podstawie tego pliku JAR.
Tworzenie klasy testowej (D)
Stwórzmy test hello world, który po prostu zrzuca wiadomość na standardowe wyjście. Testy oparte na handlu generalnie implementują interfejs IRemoteTest . Oto implementacja HelloWorldTest:
package com.android.tradefed.example; import com.android.tradefed.device.DeviceNotAvailableException; import com.android.tradefed.invoker.TestInformation; import com.android.tradefed.log.LogUtil.CLog; import com.android.tradefed.result.ITestInvocationListener; import com.android.tradefed.testtype.IRemoteTest; public class HelloWorldTest implements IRemoteTest { @Override public void run(TestInformation testInfo, ITestInvocationListener listener) throws DeviceNotAvailableException { CLog.i("Hello, TF World!"); } }
Zapisz ten przykładowy kod do <tree>/tools/tradefederation/core/src/com/android/tradefed/example/HelloWorldTest.java
i odbuduj tradefed z twojej powłoki:
m -jN
Zauważ, że CLog.i
w powyższym przykładzie jest używany do kierowania wyjścia do konsoli. Więcej informacji na temat logowania do Federacji Handlowej znajduje się w rozdziale Logowanie (D, I, R) .
Jeśli kompilacja nie powiedzie się, skonsultuj się z konfiguracją komputera, aby upewnić się, że nie przegapiłeś żadnego kroku.
Tworzenie konfiguracji (I)
Testy Federacji Handlowej stają się wykonalne, tworząc plik Configuration , plik XML, który instruuje handel, który test (lub testy) należy uruchomić, a także jakie inne moduły należy wykonać i w jakiej kolejności.
Stwórzmy nową konfigurację dla naszego HelloWorldTest (zwróć uwagę na pełną nazwę klasy HelloWorldTest):
<configuration description="Runs the hello world test"> <test class="com.android.tradefed.example.HelloWorldTest" /> </configuration>
Zapisz te dane w pliku helloworld.xml
w dowolnym miejscu w lokalnym systemie plików (np. /tmp/helloworld.xml
). TF przeanalizuje plik konfiguracyjny XML (aka config ), załaduje określoną klasę za pomocą odbicia, utworzy jej instancję, rzuci ją na IRemoteTest
i wywoła jego metodę run
.
Uruchamianie konfiguracji (R)
W swojej powłoce uruchom konsolę z wymianą:
tradefed.sh
Upewnij się, że urządzenie jest podłączone do maszyny hosta i jest widoczne dla handlu:
tf> list devices Serial State Product Variant Build Battery 004ad9880810a548 Available mako mako JDQ39 100
Konfiguracje można wykonać za pomocą polecenia run <config>
. Próbować:
tf> run /tmp/helloworld.xml 05-12 13:19:36 I/TestInvocation: Starting invocation for target stub on build 0 on device 004ad9880810a548 Hello, TF World!
Powinieneś zobaczyć "Hello, TF World!" wyjście na terminalu.
Możesz potwierdzić, że polecenie zostało uruchomione, używając list invocations
lub li
w wierszu poleceń i nie powinno niczego drukować. Jeśli polecenia są aktualnie uruchomione, wyświetlają się w następujący sposób:
tf >l i Command Id Exec Time Device State 10 0m:00 [876X00GNG] running stub on build(s) 'BuildInfo{bid=0, target=stub, serial=876X00GNG}'
Dodanie konfiguracji do ścieżki klas (D, I, R)
Dla wygody wdrażania można również pakować konfiguracje do samych plików JAR podlegających wymianie. Tradefed automatycznie rozpoznaje wszystkie konfiguracje umieszczone w folderach konfiguracyjnych na ścieżce klas.
Aby to zilustrować, przenieś plik helloworld.xml do biblioteki podstawowej helloworld.xml
( <tree>/tools/tradefederation/core/res/config/example/helloworld.xml
). Odbuduj tradefed, uruchom ponownie konsolę tradefed, a następnie poproś tradefed o wyświetlenie listy konfiguracji ze ścieżki klas:
tf> list configs […] example/helloworld: Runs the hello world test
Możesz teraz uruchomić konfigurację helloworld za pomocą:
tf> run example/helloworld 05-12 13:21:21 I/TestInvocation: Starting invocation for target stub on build 0 on device 004ad9880810a548 Hello, TF World!
Interakcja z urządzeniem (D, R)
Jak dotąd nasz HelloWorldTest nie robi nic ciekawego. Specjalnością Tradefed jest przeprowadzanie testów na urządzeniach z Androidem, więc dodajmy do testu urządzenie z Androidem.
Testy mogą uzyskać odwołanie do urządzenia z systemem Android przy użyciu TestInformation
, dostarczanego przez platformę, gdy wywoływana jest metoda IRemoteTest#run
.
Zmodyfikujmy komunikat wydruku HelloWorldTest, aby wyświetlał numer seryjny urządzenia:
@Override public void run(TestInformation testInfo, ITestInvocationListener listener) throws DeviceNotAvailableException { CLog.i("Hello, TF World! I have device " + testInfo.getDevice().getSerialNumber()); }
Teraz przebuduj tradefed i sprawdź listę urządzeń:
tradefed.sh
tf> list devices Serial State Product Variant Build Battery 004ad9880810a548 Available mako mako JDQ39 100
Zanotuj numer seryjny podany jako Dostępny ; czyli urządzenie, które powinno być przydzielone do HelloWorld:
tf> run example/helloworld 05-12 13:26:18 I/TestInvocation: Starting invocation for target stub on build 0 on device 004ad9880810a548 Hello, TF World! I have device 004ad9880810a548
Powinieneś zobaczyć nowy komunikat drukowania z numerem seryjnym urządzenia.
Wysyłanie wyników testu (D)
IRemoteTest
zgłasza wyniki, wywołując metody w instancji ITestInvocationListener dostarczonej do metody #run
. Sama struktura TF jest odpowiedzialna za raportowanie początku (za pośrednictwem ITestInvocationListener#invocationStarted ) i końca (za pośrednictwem ITestInvocationListener#invocationEnded ) każdego wywołania.
Przebieg testowy to logiczny zbiór testów. Aby zgłosić wyniki testu, IRemoteTest
jest odpowiedzialny za zgłaszanie rozpoczęcia przebiegu testowego, początku i końca każdego testu oraz zakończenia przebiegu testowego.
Oto jak implementacja HelloWorldTest może wyglądać z pojedynczym nieudanym wynikiem testu.
@Override public void run(TestInformation testInfo, ITestInvocationListener listener) throws DeviceNotAvailableException { CLog.i("Hello, TF World! I have device " + testInfo.getDevice().getSerialNumber()); TestDescription testId = new TestDescription("com.example.TestClassName", "sampleTest"); listener.testRunStarted("helloworldrun", 1); listener.testStarted(testId); listener.testFailed(testId, "oh noes, test failed"); listener.testEnded(testId, Collections.emptyMap()); listener.testRunEnded(0, Collections.emptyMap()); }
TF zawiera kilka implementacji IRemoteTest
, których możesz użyć ponownie zamiast pisać własne od zera. Na przykład InstrumentationTest może zdalnie uruchamiać testy aplikacji systemu Android na urządzeniu z systemem Android, analizować wyniki i przesyłać je dalej do ITestInvocationListener
). Aby uzyskać szczegółowe informacje, zobacz Typy testów .
Przechowywanie wyników badań (I)
Domyślną implementacją odbiornika testowego dla konfiguracji TF jest TextResultReporter , która zrzuca wyniki wywołania na standardowe wyjście. Aby to zilustrować, uruchom konfigurację HelloWorldTest z poprzedniej sekcji:
./tradefed.sh
tf> run example/helloworld 04-29 18:25:55 I/TestInvocation: Invocation was started with cmd: /tmp/helloworld.xml 04-29 18:25:55 I/TestInvocation: Starting invocation for 'stub' with '[ BuildInfo{bid=0, target=stub, serial=876X00GNG} on device '876X00GNG'] 04-29 18:25:55 I/HelloWorldTest: Hello, TF World! I have device 876X00GNG 04-29 18:25:55 I/InvocationToJUnitResultForwarder: Running helloworldrun: 1 tests 04-29 18:25:55 W/InvocationToJUnitResultForwarder: Test com.example.TestClassName#sampleTest failed with stack: oh noes, test failed 04-29 18:25:55 I/InvocationToJUnitResultForwarder: Run ended in 0 ms
Aby przechowywać wyniki wywołania w innym miejscu, na przykład w pliku, określ niestandardową implementację ITestInvocationListener
przy użyciu tagu result_reporter
w konfiguracji.
TF zawiera również odbiornik XmlResultReporter , który zapisuje wyniki testów do pliku XML w formacie podobnym do używanego przez program zapisywania XML JUnit . Aby określić wynik_reporter w konfiguracji, edytuj konfigurację …/res/config/example/helloworld.xml
:
<configuration description="Runs the hello world test"> <test class="com.android.tradefed.example.HelloWorldTest" /> <result_reporter class="com.android.tradefed.result.XmlResultReporter" /> </configuration>
Teraz odbuduj handel i ponownie uruchom próbkę Hello World:
tf> run example/helloworld 05-16 21:07:07 I/TestInvocation: Starting invocation for target stub on build 0 on device 004ad9880810a548 Hello, TF World! I have device 004ad9880810a548 05-16 21:07:07 I/XmlResultReporter: Saved device_logcat log to /tmp/0/inv_2991649128735283633/device_logcat_6999997036887173857.txt 05-16 21:07:07 I/XmlResultReporter: Saved host_log log to /tmp/0/inv_2991649128735283633/host_log_6307746032218561704.txt 05-16 21:07:07 I/XmlResultReporter: XML test result file generated at /tmp/0/inv_2991649128735283633/test_result_536358148261684076.xml. Total tests 1, Failed 1, Error 0
Zwróć uwagę na komunikat dziennika informujący, że wygenerowano plik XML; wygenerowany plik powinien wyglądać tak:
<?xml version='1.0' encoding='UTF-8' ?> <testsuite name="stub" tests="1" failures="1" errors="0" time="9" timestamp="2011-05-17T04:07:07" hostname="localhost"> <properties /> <testcase name="sampleTest" classname="com.example.TestClassName" time="0"> <failure>oh noes, test failed </failure> </testcase> </testsuite>
Możesz także napisać własne niestandardowe detektory wywołań — wystarczy zaimplementować interfejs ITestInvocationListener .
Tradefed obsługuje wiele detektorów wywołań, dzięki czemu możesz wysyłać wyniki testów do wielu niezależnych miejsc docelowych. Aby to zrobić, po prostu określ wiele tagów <result_reporter>
w swojej konfiguracji.
Logowanie (D, I, R)
Urządzenia rejestrujące TF obejmują możliwość:
- Przechwytuj logi z urządzenia (aka logcat urządzenia)
- Rejestruj dzienniki ze struktury Federacji Handlowej działającej na komputerze hosta (inaczej dziennik hosta)
Struktura TF automatycznie przechwytuje logcat z przydzielonego urządzenia i wysyła go do nasłuchiwania wywołania w celu przetworzenia. XmlResultReporter
następnie zapisuje przechwycony dziennik urządzenia jako plik.
Dzienniki hosta TF są zgłaszane przy użyciu opakowania CLog dla klasy Log ddmlib. Skonwertujmy poprzednie wywołanie System.out.println
w HelloWorldTest na wywołanie CLog
:
@Override public void run(ITestInvocationListener listener) throws DeviceNotAvailableException { CLog.i("Hello, TF World! I have device %s", getDevice().getSerialNumber());
CLog
obsługuje bezpośrednio interpolację ciągów, podobnie jak String.format
. Po przebudowaniu i ponownym uruchomieniu TF powinieneś zobaczyć komunikat dziennika na standardowe wyjście:
tf> run example/helloworld … 05-16 21:30:46 I/HelloWorldTest: Hello, TF World! I have device 004ad9880810a548 …
Domyślnie, tradefed wysyła komunikaty dziennika hosta do stdout . TF zawiera również implementację dziennika, która zapisuje komunikaty do pliku: FileLogger . Aby dodać rejestrowanie plików, dodaj tag logger
do konfiguracji, określając pełną nazwę klasy FileLogger
:
<configuration description="Runs the hello world test"> <test class="com.android.tradefed.example.HelloWorldTest" /> <result_reporter class="com.android.tradefed.result.XmlResultReporter" /> <logger class="com.android.tradefed.log.FileLogger" /> </configuration>
Teraz przebuduj i uruchom ponownie przykład helloworld:
tf >run example/helloworld … 05-16 21:38:21 I/XmlResultReporter: Saved device_logcat log to /tmp/0/inv_6390011618174565918/device_logcat_1302097394309452308.txt 05-16 21:38:21 I/XmlResultReporter: Saved host_log log to /tmp/0/inv_6390011618174565918/host_log_4255420317120216614.txt …
Komunikat dziennika wskazuje ścieżkę dziennika hosta, który po wyświetleniu powinien zawierać komunikat dziennika HelloWorldTest:
more /tmp/0/inv_6390011618174565918/host_log_4255420317120216614.txt
Przykładowe dane wyjściowe:
… 05-16 21:38:21 I/HelloWorldTest: Hello, TF World! I have device 004ad9880810a548
Opcje obsługi (D, I, R)
Obiekty ładowane z konfiguracji TF (inaczej obiekty konfiguracyjne ) mogą również odbierać dane z argumentów wiersza poleceń za pomocą adnotacji @Option
.
Aby wziąć udział, klasa obiektu Configuration stosuje adnotację @Option
do pola członkowskiego i nadaje mu unikatową nazwę. Umożliwia to wypełnienie tej wartości pola członkowskiego za pomocą opcji wiersza polecenia (a także automatycznie dodaje tę opcję do systemu pomocy konfiguracji).
Uwaga: Nie wszystkie typy pól są obsługiwane. Aby uzyskać opis obsługiwanych typów, zobacz OptionSetter .
Dodajmy @Option
do HelloWorldTest:
@Option(name="my_option", shortName='m', description="this is the option's help text", // always display this option in the default help text importance=Importance.ALWAYS) private String mMyOption = "thisisthedefault";
Następnie dodajmy komunikat dziennika, aby wyświetlić wartość opcji w HelloWorldTest, abyśmy mogli zademonstrować, że została odebrana poprawnie:
@Override public void run(ITestInvocationListener listener) throws DeviceNotAvailableException { … CLog.logAndDisplay(LogLevel.INFO, "I received option '%s'", mMyOption);
Na koniec przebuduj TF i uruchom helloworld; powinieneś zobaczyć komunikat dziennika z domyślną wartością my_option
:
tf> run example/helloworld … 05-24 18:30:05 I/HelloWorldTest: I received option 'thisisthedefault'
Przekazywanie wartości z wiersza poleceń
Przekaż wartość my_option
; powinieneś zobaczyć my_option
wypełnione tą wartością:
tf> run example/helloworld --my_option foo … 05-24 18:33:44 I/HelloWorldTest: I received option 'foo'
Konfiguracje TF zawierają również system pomocy, który automatycznie wyświetla tekst pomocy dla pól @Option
. Wypróbuj teraz, a powinieneś zobaczyć tekst pomocy dla my_option
:
tf> run example/helloworld --help Printing help for only the important options. To see help for all options, use the --help-all flag cmd_options options: --[no-]help display the help text for the most important/critical options. Default: false. --[no-]help-all display the full help text for all options. Default: false. --[no-]loop keep running continuously. Default: false. test options: -m, --my_option this is the option's help text Default: thisisthedefault. 'file' logger options: --log-level-display the minimum log level to display on stdout. Must be one of verbose, debug, info, warn, error, assert. Default: error.
Zwróć uwagę na komunikat o „drukowaniu tylko ważnych opcji”. Aby zmniejszyć bałagan w pomocy opcji, TF używa atrybutu Option#importance
, aby określić, czy wyświetlać konkretny tekst pomocy pola @Option
, gdy podano --help
. --help-all
zawsze pokazuje pomoc dla wszystkich pól @Option
, niezależnie od ważności. Aby uzyskać szczegółowe informacje, zobacz Option.Importance .
Przekazywanie wartości z konfiguracji
Możesz również określić wartość Option w konfiguracji, dodając element <option name="" value="">
. Przetestuj go za pomocą helloworld.xml
:
<test class="com.android.tradefed.example.HelloWorldTest" > <option name="my_option" value="fromxml" /> </test>
Ponowne budowanie i uruchamianie helloworld powinno teraz generować następujące dane wyjściowe:
05-24 20:38:25 I/HelloWorldTest: I received option 'fromxml'
Pomoc konfiguracji powinna również zostać zaktualizowana, aby wskazać domyślną wartość my_option
:
tf> run example/helloworld --help test options: -m, --my_option this is the option's help text Default: fromxml.
Inne obiekty konfiguracyjne zawarte w konfiguracji helloworld, takie jak FileLogger
, również akceptują opcje. Opcja --log-level-display
jest interesująca, ponieważ filtruje logi wyświetlane na standardowe wyjście. Wcześniej w samouczku mogłeś zauważyć, że komunikat dziennika „Hello, TF World! Mam urządzenie…” przestał być wyświetlany na stdout po przełączeniu na używanie FileLogger
. Możesz zwiększyć szczegółowość logowania do stdout, przekazując --log-level-display
argument --log-level-display
.
Wypróbuj to teraz, a oprócz tego, że jesteś zalogowany do pliku, na standardowe wyjście powinien pojawić się komunikat dziennika „Mam urządzenie”:
tf> run example/helloworld --log-level-display info … 05-24 18:53:50 I/HelloWorldTest: Hello, TF World! I have device 004ad9880810a548
To wszystko, ludzie!
Przypominamy, że jeśli coś utkniesz, kod źródłowy Federacji Handlowej zawiera wiele przydatnych informacji, które nie są ujawnione w dokumentacji. Jeśli wszystko inne zawiedzie, spróbuj zadać pytanie w Grupie dyskusyjnej Google dla platformy Android , wpisując w tytule wiadomości „Federacja handlowa”.